正如评论中指出的,您可以在新线程中使用Queue http://docs.python.org/library/queue.html。缺点是您仍然需要某种方式来访问最终结果(什么fmin
最后返回)。我下面的示例使用可选回调来执行某些操作(另一个选项是也生成它,尽管您的调用代码必须区分迭代结果和最终结果):
from thread import start_new_thread
from Queue import Queue
def 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
Update:要阻止下一次迭代的执行,直到消费者完成上一次迭代的处理,还需要使用task_done
and 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