从线程获取第一个结果

时间:2014-12-24 18:02:15

标签: python multithreading asynchronous return

我有一个由for循环组成的函数,它需要很长时间来处理每个元素。

在这个循环中我只关心如果我找到一个结果或者没有结果,那么循环的执行顺序无关紧要。

如果没有找到结果,它只需要处理所有元素。

我的代码看起来像这样:

import random
from time import sleep

class Elements:
    def __init__(self,id):
        self.id = id

    def analyze(self,result):
        sleep(random.random()/2)
        if result > 0.9:
            return True

    def get_result(self):
        sleep(random.random()/2)
        return random.random()

def long_process(element):
    result = element.get_result()
    print element.id,result
    if element.analyze(result) == True:
        return element, result
    results.append(result)

if __name__ == '__main__':
    elements = []
    for n in xrange(10):
        elements.append(Elements(n))

    results = []
    desired = None
    for element in elements:
        desired = long_process(element)
        if desired:
            break
    if desired:
        print desired
    else:
        print sorted(results,reverse=True)[0]

如果找到元素中的所需元素,则输出:

0 0.150771147344
1 0.510095601312
2 0.28908099464
3 0.410008760093
4 0.435872688389
5 0.960307534462
(<__main__.Elements instance at 0x02311AD0>, 0.9603075344618438)

如果没有,它会说出来:

0 0.361404239639
1 0.207105823026
2 0.851923103243
3 0.720462633138
4 0.58273657804
5 0.380394809851
6 0.590615590942
7 0.130172801534
8 0.57736519194
9 0.597338819896
0.851923103243 # the best element 

我正在尝试使用多处理池来处理单独线程中的每个元素。但是我没有达到预期的效果。

这是我尝试过的。

def long_process(element):
    result = element.get_result()
    print element.id,result, element.analyze(result)
    if element.analyze(result) == True:
        return element, result
    results.append(result)

if __name__ == '__main__':
    # freeze_support()
    pool = Pool(processes=2)
    results = []
    pool.imap_unordered(long_process,elements)
    pool.close()
    pool.join()
    print sorted(results)[0]

输出:

0 0.257371095047 None
1 0.8533933601 None
2 0.74433029726 None
3 0.138217827732 None
5 1 True
6 0.961344251697 True
4 0.0664381718173 None
7 0.000891701766875 None
9 1 True
8 0.771957314202 None
Traceback (most recent call last):
  File "C:/User/user/Documents/Python/threading_test.py", line 40, in <module>
    print sorted(results)[0]
IndexError: list index out of range

但这有两个问题:

  • 它应该在第5个元素中停止,并将其返回。
  • 如果未找到True,则应将所有结果存储在结果列表中。

它确实以无序顺序工作(id 2,3,5,6,4 ...),它得到的结果,但是当分析为真(5 1真)时它不会停止, 并且都没有将结果附加到结果列表。[IndexError]

我尝试使用Pool.apply_async,但我也无法获取结果。

1 个答案:

答案 0 :(得分:0)

使用代码很难,所以我使用apply_async做了一个非常简单的函数示例:

from multiprocessing.pool import Pool
# habit, you can use a flag instead ...
from threading import Event
import sys

# tell everyone we're done
done = Event()
# aggregate results here
results = []
success = []

每个进程都返回一个结果,无论如何:

def is7(x):
    if x == 7:
        return (x, True, )
    return x

这是对每个结果应用的回调,在apply_async的结果返回时使用

def handle_result(x):
    if type(x) is tuple:
        # a tuple is necessarily the result we want, so we're done here.
        done.set()
        # stop pool
        p.terimnate()
        success.append(x)
        return
    results.append(x)

这是我们遍历项目(其中1000个)并在每个项目上应用函数is7的地方。如果他们中的任何人找到了解决方案,我们会立即停止并通知

p = Pool()
def run_processes():
    for element in range(0, 1000):
        print "trying %s" % str(element)
        p.apply_async(func=is7, args=(element,), callback=handle_result)

    # wait for completion
    p.close()
    p.join()
# start dispatchig tasks to pool
run_processes()
if done.isSet():
    # result may contain more than one, if two success tasks were executed closely
    print "Found result: %s" % str(success)
else:
    print "No results found, here is the list: %s " % str(results)

注意:无法保证循环将在7处完全停止,因为异步调度任务,它可能会在7之后停止一些项目。