среда, 7 августа 2013 г.

Заметка про DeferredList

DiferredList объединяет группу deferred'ов в один callback. Прослеживает все deferred'ы по их callback'ам и создает единый callback, который сразу же выполняется. Если выполнение прошло успешно, то возвращается кортеж: (success, result), где success -- булевская переменная успешного или не успешного состояния.
Особенность: после того как deferred был положен в DeferredList, им можно пользоваться и в дальнейшем.





1. Зачем нужен?
Иногда мы хоть получить информацию о различных событиях, которые скоро произойдут, раньше, чем ждать этих событий по очереди. Например, мы хотим подождать все соединения в списке на закрытие. Один из способов сделать это -- DeferredList.

2. Создание:
dl = defer.DeferredList([deferred1, deferred2, deferred3])
Обращаться с DeferredList можно также как с обычным Deferred, т.е. вызывать у него callback, errback, добавлять их и т.д.

3. Стандартное поведение:
DeferredList вызовет общий callback тогда, когда все deferred'ы будут завершены. Callback будет вызван со списком результатов каждого из входящих Deferred'ов.
Стандартный DeferredList никогда не вызовет errback'ов, которые произошли внутри переданного списка Deferred'ов. Но иногда, такое поведение не удобно. Поэтому есть опция consumeErrors, которую можно установить в True, и тогда ни один errback пропущен не будет.

4. Заметка внутри заметки:
Если мы хотим применить callback к индивидуальному deferred'у, который включен в DeferredList, мы должны добавить его callback ДО того, как положим этот deferred в DeferredList. Все потому, что иначе результат callback'a индивидуального deferred'a не вернется в общий callback, который относится к DeferredList.

Пример:
Хотим применить индивидуальный callback addTen к deferred1 (помимо общего callback'a printResult):

def printResult(result):
    print result
def addTen(result):
    return result + " ten"

# Deferred получает callback до того, как DeferredList был создан
deferred1 = defer.Deferred()
deferred2 = defer.Deferred()
deferred1.addCallback(addTen)
dl = defer.DeferredList([deferred1, deferred2])
dl.addCallback(printResult)
deferred1.callback("one") # вызывает addTen, проверяет DeferredList, сохраняет "one ten"
deferred2.callback("two")
# dl вызовет callback и напечатается:
#     [(1, 'one ten'), (1, 'two')]

# Deferred получает callback после того, как DeferredList был создан
deferred1 = defer.Deferred()
deferred2 = defer.Deferred()
dl = defer.DeferredList([deferred1, deferred2])
deferred1.addCallback(addTen) # будет запущено после того, как DeferredList получит это значение
dl.addCallback(printResult)
deferred1.callback("one") # проверяет DeferredList, сохраняет "one", вызывает addTen
deferred2.callback("two")
# dl вызовет callback и напечатается:
#     [(1, 'one), (1, 'two')]

5. Нестандартное поведение:
DeferredList принимает еще 2 ключевых слова, которые позволяют изменить его стандартное поведение:
- fireOnOneCallback. DeferredList запустит свой callback уже тогда, когда будет запущен один из callback'ов индивидуальных Deferred'ов (индивидуальный Deferred - т.е. тот одиночный deferred, который мы добавили при создании DeferredList'a)
- fireOnOneErrback. Аналогично fireOnOneCallback. Вызов errback DeferredList'a произойдет, как только будет вызван один из errback'ов индивидуальных deferred'ов. Обычно используется, когда вы хотите дождаться всех результатов сразу, но среагировать на какую-то ошибку внутри любого из индивидуальных deferred'ов.

consumeErrors - параметр, который не меняет поведение DeferredList'а, но позволит увидеть любую ошибку внутри цепи индивидуальных deferred'ов. Этот параметр предотвратит "Unhandled error in Deferred" предупреждение в deferred'ах, без добавления в каждый из них персональных errback'ов.



Всего лишь неточный перевод части документации отсюда и отсюда.

Комментариев нет:

Отправить комментарий