如注释中所指出的,您可以使用在新线程中进行操作
Queue。缺点是您仍然需要某种方法来访问最终结果(最后
fmin返回什么)。下面的示例使用一个可选的回调函数来做一些事情(另一个选择就是也产生它,尽管您的调用代码必须区分迭代结果和最终结果):
from thread import start_new_threadfrom Queue import Queuedef my_fmin(func, x0, end_callback=(lambda x:x), timeout=None): q = Queue() # fmin produces, the generator consumes job_done = object() # signals the processing is done # Producer def my_callback(x): q.put(x) def task(): ret = scipy.optimize.fmin(func,x0,callback=my_callback) q.put(job_done) end_callback(ret) # "Returns" the result of the main call # Starts fmin in a new thread start_new_thread(task,()) # Consumer while True: next_item = q.get(True,timeout) # Blocks until an input is available if next_item is job_done: break yield next_item
更新: 要阻止下一次迭代的执行,直到使用者完成对最后一个迭代的处理为止,还必须使用
task_done和
join。
# Producer def my_callback(x): q.put(x) q.join() # Blocks until task_done is called # Consumer while True: next_item = q.get(True,timeout) # Blocks until an input is available if next_item is job_done: break yield next_item q.task_done() # Unblocks the producer, so a new iteration can start
请注意,这
maxsize=1是不必要的,因为直到消耗完最后一个项目,才会有新项目添加到队列中。
更新2:
还请注意,除非最终所有生成器都检索到该生成器,否则创建的线程将死锁(它将永远阻塞并且其资源将永远不会释放)。生产者正在等待队列,并且由于它存储对该队列的引用,因此即使消费者使用,它也不会被gc回收。然后,队列将变得不可访问,因此没有人能够释放该锁。
如果可能的话,一个干净的解决方案还是个未知数(因为它取决于代替的特定功能
fmin)。可以使用解决方法
timeout,如果
put阻塞时间过长,则使生产者引发异常:
q = Queue(maxsize=1) # Producer def my_callback(x): q.put(x) q.put("dummy",True,timeout) # Blocks until the first result is retrieved q.join() # Blocks again until task_done is called # Consumer while True: next_item = q.get(True,timeout) # Blocks until an input is available q.task_done() # (one "task_done" per "get") if next_item is job_done: break yield next_item q.get() # Retrieves the "dummy" object (must be after yield) q.task_done() # Unblocks the producer, so a new iteration can start


