Найти - Пользователи
Полная версия: twisted, генерация Deferred
Начало » Python для экспертов » twisted, генерация Deferred
1 2
svas
Есть две функции: одна долго работает с файловой системой, другая исполняет запрос к базе данных и в зависимости от результата, либо ничего не возвращает, либо бросает исключение. Нужно первую функцию запустить в отдельном потоке и паралельно с ней выполнить запрос к базе данных. Взависимости от результата обеих фукнций, нужно вызвать или callback (если обе функции завершились удачно) или errback (если хотя бы одна из функций завершилась неудачно). Как такое можно реализовать? Как по отдельности это сделать я знаю.
from twisted.internet import defer, reactor
from twisted.internet import threads
import time
import sys

def execute_query(param):
def _query_result_callback(res):
sys.stderr.write('query result callback. res - %s\n' % str(res))
return res

sys.stderr.write('executing query, param - %s\n' % (param))
d = defer.succeed(param)
d.addCallback(_query_result_callback)
return d

def work_with_filesystem(param):
raise Exception(param)
sys.stderr.write('work with fyle system, param - %s\n' % param)
time.sleep(1.0)
return param

def callback(param):
sys.stderr.write('callback, param - %s\n' % param)

def errback(f):
sys.stderr.write('errback, param - %s\n' % (str(f.value)))

d1 = execute_query('d1')
d1.addCallback(callback)
d1.addErrback(errback)

d2 = threads.deferToThread(work_with_filesystem, 'd2')
d2.addCallback(callback)
d2.addErrback(errback)

reactor.callLater(5, reactor.stop)
reactor.run()
Нужно как-то объединить deferreds d1 и d2
Так работает, но функции вызываются последовательно
from twisted.internet import defer, reactor
from twisted.internet import threads
import time
import sys

def execute_query(param):
def _query_result_callback(res):
sys.stderr.write('query result callback. res - %s\n' % str(res))
return res

sys.stderr.write('executing query, param - %s\n' % (param))
d = defer.succeed(param)
d.addCallback(_query_result_callback)
return d

def work_with_filesystem(param):

sys.stderr.write('work with fyle system, param - %s\n' % param)
time.sleep(1.0)
return param

def callback(param):
sys.stderr.write('callback, param - %s\n' % param)

def errback(f):
sys.stderr.write('errback, param - %s\n' % (str(f.value)))

d = threads.deferToThread(work_with_filesystem, 'qwe')
d.addCallback(execute_query)
d.addCallback(callback)
d.addErrback(errback)

reactor.callLater(5, reactor.stop)
reactor.run()
bw
d1 = threads.deferToThread(execute_query, 'd1')
d2 = threads.deferToThread(work_with_filesystem, 'd2')

defer.DeferredList([d1, d2])\
.addCallback(callback)\
.addErrback(errback)
..bw
svas
Ошибка:assert not isinstance(result, Deferred).
svas
Че-то не понимаю я эти Deferred
В документации сказано:
When the result is ready, give it to the Deferred object. .callback(result) if the operation succeeded, .errback(failure) if it failed. Note that failure is typically an instance of a
twisted.python.failure.Failure instance.

Deferred object triggers previously-added (call/err)back with the result or failure. Execution then follows the following rules, going down the chain of callbacks to be processed.

Result of the callback is always passed as the first argument to the next callback, creating a chain of processors.

If a callback raises an exception, switch to errback.

An unhandled failure gets passed down the line of errbacks, this creating an asynchronous analog to a series to a series of except: statements.

If an errback doesn't raise an exception or return a twisted.python.failure.Failure instance, switch to callback.
последнюю строчку я перевожу примерное так
Если errback не запускает исключение или возвращает экземпляр twisted.python.failure.Failure, переключаемся на callback
Как должен работать такой код? Как я понимаю, если первый errback не запускает исключение и не возвращает …Failure, то должны запускаться callback'и.
from twisted.internet import defer, reactor
from twisted.internet import threads
import time
import sys


def some_func():
sys.stderr.write('some func\n')
return defer.Deferred()

def callback1(*args):
sys.stderr.write('callback1\n')

def callback2(*args):
sys.stderr.write('callback2\n')

def callback3(*args):
sys.stderr.write('callback3\n')

def errback1(*args):
sys.stderr.write('errback1\n')

def errback2(*args):
sys.stderr.write('errback2\n')

d = some_func()
d.addCallback(callback1)
d.addCallback(callback2)
d.addCallback(callback3)

d.addErrback(errback1)
d.addErrback(errback2)

d.errback(123)
#d.callback(123)


reactor.callLater(5, reactor.stop)
reactor.run()
Выводится
some func
errback1
Если вызывать не errback а callback и в callback1 запустить исключение ничего не меняется. Что я не понимаю?
svas
Я знаю что есть документация. Цитата, которую я привел - с этой страницы. Если знаете почему работает не так как я думаю должно, скажите.
Андрей Светлов
Для
d = some_func()
d.addCallback(callback1)
d.addCallback(callback2)
d.addCallback(callback3)

d.addErrback(errback1)
d.addErrback(errback2)

d.errback(123)
#d.callback(123)
Поток будет:

c1 c2 c3 —————->
/
——————-> e2 e2

Что вам непонятно?
svas
Непонятна последняя строчка в документации, которую я привел.
If an errback doesn't raise an exception or return a twisted.python.failure.Failure instance, switch to callback.
Как я ее перевел
Если errback не запускает исключение или возвращает экземпляр twisted.python.failure.Failure, переключаемся на callback
Я понимаю это так: вызывается первый errback, он не запускает исключение и не возвращает Failure, то должен запускаться callback2. Может я неправильно перевел?

Разобрался, спасибо
Почему-то не работал такой код
d = some_func()
d.addCallback(callback1)
d.addErrback(errback1)
d.addCallback(callback2)
d.addErrback(errback2)
d.addCallback(callback3)

d.errback(123)
callback2 и callback3 не вызывались
agalen
svas
callback2 и callback3 не вызывались
Этот код выводит результат:
some func
errback1
callback2
callback3
svas
Ну да. Так и должно быть.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB