我有一个协同应该同时执行一些任务:
@gen.coroutine
def scrape_trackers(self):
yield [self.scrape_tracker(tracker) for tracker in self.torrent.trackers]
有些跟踪器永远不会响应(或者可能在一小时内响应),因此我的代码永远不会超过此方法,因为Tornado正在等待所有的完成。我如何只等待一个完成并继续在后台尝试其他?
类似的东西:
yield WhenAnyComplete(map(self.scrape_tracker, self.torrent.trackers))
我正在考虑用IOLoop.add_callback()
调用每个方法并在完成时做一些事情,但我不完全确定从哪里开始:
for tracker in self.torrent.trackers:
future = self.scrape_tracker(tracker)
IOLoop.add_future(future, self.tracker_scraped)
感谢任何帮助。
答案 0 :(得分:0)
我能想到的最好的方法是返回一个新的Future
并且第一次成功的函数调用给它一个结果:
def scrape_trackers(self):
result = Future()
for tracker in self.torrent.trackers:
future = self.scrape_tracker(tracker)
future.add_done_callback(lambda f: self.tracker_done(f, result))
return result
def tracker_done(self, future, result_future):
if future.exception():
logging.warning('Tracker could not be scraped: %s', future.exception())
return
logging.info('Scraped tracker %s', future)
if self.unconnected_peers:
result_future.set_result(True)
答案 1 :(得分:0)
yieldpoints库具有WaitAny
功能。它早于Tornado使用Futures
,所以现在使用起来有点麻烦。最好查看yieldpoints.WaitAny
和tornado.gen.YieldFuture
的来源,以便将两者混合起来。
或者,您可以重新组织代码,以便不再需要WaitAny
。而不是在完成结果时剥离结果的一个协程,只需为每个任务启动一个新的协程并在最后加入它们:
@gen.coroutine
def process_tracker(self, tracker):
result = yield self.scrape_tracker(tracker)
# Do whatever you'd do after WaitAny here. All the process_tracker
# calls can proceed in parallel as their results are ready.
@gen.coroutine
def process_all_trackers(self, trackers):
yield [self.process_tracker(t) for t in trackers]