2012-07-09 113 views
0

这是一样的取景器上的Windows,但使用线程来获得更快,线程,多处理错误

import os,threading,multiprocessing 


    def finder(path,q): 
    for x in os.walk(unicode(path)): 
     if x[1]: 
     for dirname in x[1]: 
     if target in dirname.lower(): 
     q.put(os.path.join(x[0],dirname)) 
     if x[2]: 
     for name in x[2]: 
     if target in name.lower(): 
     q.put(os.path.join(x[0],name)) 

    q.put(1) 

    def printer(q): 
    cmd=0 
    while 1: 
     tmp=q.get() 
     if tmp==1: 
     cmd += 1 
     continue 
     if cmd ==thnum: 
     break 
     print tmp 

    if __name__ =="__main__": 
    q=multiprocessing.JoinableQueue() 
    ini=os.walk(u"C:\\").next() 
    thnum=len(ini[1]) 
    target=raw_input("what you wanna get\n") 

    p=multiprocessing.Process(target=printer,args=(q,)) 
    p.daemon=1 
    p.start() 

    for i in xrange(thnum): 
     t=threading.Thread(target=finder,args=(ini[1][i],q,)) 
     t.start() 
     print i," started" 
    q.join() 

它显示

0开始 1日开始 .... 22开始

但从未显示结果 所以我的问题是

  1. 为什么没有结果显示
  2. 我知道代码很脏:(...是一个干净的方式来做到这一点?

谢谢你们。

+0

查看[Python风格指南](http://www.python.org/dev/peps/pep-0008/),了解如何编写“干净”代码的示例。 – 2012-07-09 01:35:49

+0

另外,是什么让你觉得多线程会更快? – 2012-07-09 01:36:51

+0

@JoelCornett谢谢!但我想知道的是关于算法还是更合适的功能:) – 2012-07-09 01:41:17

回答

2

你刚才一吨的乱码在这里,也一些错误。我看到的主要问题是您的线程立即无法生成os.walk中的任何内容,并且会立即退出q.put。这是因为您不会将完整路径传递给每个线程。只有一个目录名称。但很难知道这一点,因为你不使用任何变量的描述性名称。

这里是一个清理版本:

import os 
import threading 
import multiprocessing 


def finder(path, q, done): 
    for root, dirs, files in os.walk(unicode(path)): 
     for dirname in dirs: 
      if target in dirname.lower(): 
       q.put(os.path.join(root,dirname)) 
     for name in files: 
      if target in name.lower(): 
       q.put(os.path.join(root,name)) 

    # print "Leaving thread", threading.current_thread() 
    done.put(1) 

def printer(q,done,worker_count): 
    total = 0 
    while 1: 
     try: done.get_nowait() 
     except: pass 
     else: total += 1 

     if total == worker_count: 
      break 

     try: tmp=q.get(timeout=1) 
     except: pass 

     print tmp 

if __name__ =="__main__": 

    results = multiprocessing.Queue() 
    done = multiprocessing.Queue() 
    root, dirs, files = os.walk(u"C:\\").next() 
    thnum=len(dirs) 
    target=raw_input("what you wanna get\n") 

    p=multiprocessing.Process(target=printer,args=(results,done,thnum)) 
    p.start() 

    for i in xrange(thnum): 
     full_path = os.path.join(root, dirs[i]) 
     t=threading.Thread(target=finder,args=(full_path, results, done)) 
     t.start() 

    p.join() 

见我怎么在发送到每一个线程之前一起在主块连接的完整路径?我删除了JoinableQueue因为它永远不会做你认为的事情。如果在任何时候打印机已经清除了结果队列,但线程仍在尝试查找更多,则队列会认为它已完成并退出。我用其替换的另一个队列用作信号。每个工作人员在完成后将其放入队列中。然后打印机继续检查是否可以从已完成的队列中拉出足够的信号,以等同于启动的工作人员数量。如果是这样,它将退出。

这整个事情仍然可以改写更好,但我只是应用你的东西的海带。我只是把它与你所拥有的一起扔在一起。

注意,如果只有文件,则启动整个过程的方式(检查启动路径下的目录)基本上只会退出。

+0

你是救世主!!我意识到不仅问题,而且意义重大非常感谢你 – 2012-07-09 03:24:24

+0

我的朋友不是问题雅,当我们必须检查代码时,它完全帮助我们,让人们看到描述性名称时更容易看到每一行的意图。 – jdi 2012-07-09 03:25:43

1

第二,写一个干净的多线程代码,使用装饰器可以帮助你,并使它在线程和进程之间进行切换。

检查这里decorators async decorator

的例子,您可以通过安装装饰:

easy_install decorator 

或下载代码,使用python setup.py install

+0

谢谢你的一个因素。我在抱怨为什么我可以接受两个很好的答案:( – 2012-07-09 03:25:34

+0

:P你不能,@from__future__,但你仍然可以将这个标记为“有用的” – pinkdawn 2012-07-09 04:45:54