Вы можете использовать Future, который не входит в стандартную библиотеку, но очень прост в реализации:
from threading import Thread, Event
class Future(object):
def __init__(self, thunk):
self._thunk = thunk
self._event = Event()
self._result = None
self._failed = None
Thread(target=self._run).start()
def _run(self):
try:
self._result = self._thunk()
except Exception, e:
self._failed = True
self._result = e
else:
self._failed = False
self._event.set()
def wait(self):
self._event.wait()
if self._failed:
raise self._result
else:
return self._result
Вы бы использовали эту конкретную реализацию следующим образом:
import time
def work():
for x in range(3):
time.sleep(1)
print 'Tick...'
print 'Done!'
return 'Result!'
def main():
print 'Starting up...'
f = Future(work)
print 'Doing more main thread work...'
time.sleep(1.5)
print 'Now waiting...'
print 'Got result: %s' % f.wait()
К сожалению, при использовании системы, в которой нет «основного» потока, трудно сказать, когда вызывать «wait»; очевидно, вы не хотите останавливать обработку, пока вам не понадобится ответ.
В Twisted вы можете использовать deferToThread
, что позволяет вам вернуться в основной цикл. Идиоматически эквивалентный код в Twisted будет выглядеть примерно так:
import time
from twisted.internet import reactor
from twisted.internet.task import deferLater
from twisted.internet.threads import deferToThread
from twisted.internet.defer import inlineCallbacks
def work():
for x in range(3):
time.sleep(1)
print 'Tick...'
print 'Done!'
return 'Result!'
@inlineCallbacks
def main():
print 'Starting up...'
d = deferToThread(work)
print 'Doing more main thread work...'
yield deferLater(reactor, 1.5, lambda : None)
print "Now 'waiting'..."
print 'Got result: %s' % (yield d)
хотя для того, чтобы действительно запустить реактор и выйти из него, когда он закончится, вам нужно будет сделать это также:
reactor.callWhenRunning(
lambda : main().addCallback(lambda _: reactor.stop()))
reactor.run()
Основное отличие от Twisted заключается в том, что если в главном потоке происходит больше «вещей» - другие синхронизированные события запускаются, другие сетевые соединения получают трафик, кнопки нажимаются в графическом интерфейсе - эта работа будет происходить без проблем, поскольку deferLater
и yield d
на самом деле не останавливает весь поток, они только приостанавливают "главную" inlineCallbacks
сопрограмму.