[英]How to manage python threads results?
我正在使用此代码:
def startThreads(arrayofkeywords):
global i
i = 0
while len(arrayofkeywords):
try:
if i<maxThreads:
keyword = arrayofkeywords.pop(0)
i = i+1
thread = doStuffWith(keyword)
thread.start()
except KeyboardInterrupt:
sys.exit()
thread.join()
对于python中的线程,我几乎已经完成了所有工作,但我不知道如何管理每个线程的结果,在每个线程上我都有一个字符串数组作为结果,如何安全地将所有这些数组加入一个? 因为,如果我尝试写入全局数组,两个线程可能同时写入。
使用Queue.Queue
实例,它本质上是线程安全的。 每个线程都可以.put
它的结果是全局实例时,它的完成,主线程(当它知道所有的工作线程完成后,通过.join
荷兰国际集团它们例如在@ unholysampler的答案)可循环.get
婷从每个结果它,并使用每个结果.extend
“整体结果”列表,直到队列清空为止。
编辑 :您的代码还有其他大问题 - 如果最大线程数小于关键字数量,它将永远不会终止(您尝试为每个关键字启动一个线程 - 永远不会更少 - 但如果您已经开始了你永远循环的最大数字,没有进一步的目的)。
相反,请考虑使用线程池 ,类似于此配方中的线程池 ,除了代替排队callables,您将对关键字进行排队 - 因为您想要在线程中运行的可调用在每个线程中是相同的,只是变化争论。 当然,这可赎回将改为剥离从传入任务队列(的东西.get
)和.put
完成后的结果即将离任,结果排队的名单。
要终止N个线程,您可以在所有关键字之后.put
N“sentinels”(例如None
,假设没有关键字可以是None
):如果刚刚提取的“关键字”为None
则线程的可调用将退出。
通常, Queue.Queue
提供了在Python中组织线程化(和多处理!)体系结构的最佳方式,它们是通用的,就像我指向的配方一样,或者更专业,就像我建议你的用例一样。最后两段。
首先,您实际上需要保存所有这些thread
对象以对它们调用join()
。 如上所述,您只保存最后一个,然后仅保存没有异常。
执行多线程编程的一种简单方法是为每个线程提供运行所需的所有数据,然后让它不写入该工作集之外的任何内容。 如果所有线程都遵循该指南,则它们的写入不会相互干扰。 然后,一旦线程完成, 主线程只将结果聚合到一个全局数组中。 这被称为“fork / join parallelism”。
如果您继承Thread对象,则可以为其存储该返回值的空间,而不会干扰其他线程。 然后你可以做这样的事情:
class MyThread(threading.Thread):
def __init__(self, ...):
self.result = []
...
def main():
# doStuffWith() returns a MyThread instance
threads = [ doStuffWith(k).start() for k in arrayofkeywords[:maxThreads] ]
for t in threads:
t.join()
ret = t.result
# process return value here
编辑:
看了一下之后,似乎上面的方法不是在Python中执行线程的首选方法 。 以上是线程的Java-esque模式。 相反,你可以这样做:
def handler(outList)
...
# Modify existing object (important!)
outList.append(1)
...
def doStuffWith(keyword):
...
result = []
thread = Thread(target=handler, args=(result,))
return (thread, result)
def main():
threads = [ doStuffWith(k) for k in arrayofkeywords[:maxThreads] ]
for t in threads:
t[0].start()
for t in threads:
t[0].join()
ret = t[1]
# process return value here
您需要保持指向您所创建的每个线程的指针。 因此,您的代码仅确保最后创建的线程完成。 这并不意味着你在它之前开始的所有那些也已经完成了。
def startThreads(arrayofkeywords):
global i
i = 0
threads = []
while len(arrayofkeywords):
try:
if i<maxThreads:
keyword = arrayofkeywords.pop(0)
i = i+1
thread = doStuffWith(keyword)
thread.start()
threads.append(thread)
except KeyboardInterrupt:
sys.exit()
for t in threads:
t.join()
//process results stored in each thread
这也解决了写访问的问题,因为每个线程都会在本地存储它的数据。 然后在完成所有这些操作后,您可以完成组合每个线程本地数据的工作。
我知道这个问题有点老了,但最好的方法就是不要像其他同事提出的方式那样伤害自己:)
请阅读有关Pool的参考资料。 这样你就可以加入你的工作了:
def doStuffWith(keyword):
return keyword + ' processed in thread'
def startThreads(arrayofkeywords):
pool = Pool(processes=maxThreads)
result = pool.map(doStuffWith, arrayofkeywords)
print result
如果使用信号量来保护关键部分,则写入全局数组是很好的。 当你想要附加到全局数组时,你'获得'锁定,然后在你完成时'释放'。 这样,每个只有一个线程附加到数组。
查看http://docs.python.org/library/threading.html并搜索信号量以获取更多信息。
sem = threading.Semaphore()
...
sem.acquire()
# do dangerous stuff
sem.release()
尝试一些信号量的方法,比如获取和释放.. http://docs.python.org/library/threading.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.