Уведомления

Группа в Telegram: @pythonsu

#1 Май 6, 2010 02:06:37

r1der
От:
Зарегистрирован: 2010-04-13
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

[Twisted][Source][?] Как работает именно deffered?

Как выполняются асинхронные действия внутри?(не смог сам понять по исходнику), все ведь работает в одном потоке так?, каким тогда образом например под вин или юникс-лайк работает именно асинхронность? Пожалуйста объясните.. И какие еще есть способы реализации асинхронности?(не потоки, не процессы) Спасибо заранее)



Офлайн

#2 Май 6, 2010 03:34:18

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

[Twisted][Source][?] Как работает именно deffered?

Я не знаю, что такое deffered, это раз.
Deferred это просто система callback'ов, это два.
А какие могут быть непонятки с асинхронностью? Приходит пакет по сети, вызывается callback, выполняется код, вызывается ещё один callback (например, через reactor.callLater(0.0, defer.call, some_result)) и т.д. Всё делается в единственном потоке.

..bw



Офлайн

#3 Май 6, 2010 15:34:41

r1der
От:
Зарегистрирован: 2010-04-13
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

[Twisted][Source][?] Как работает именно deffered?

на сокетах асинхронность достигается неблокируещими сокетами внутри или select().. а как выполнять асинхронно не сетевые операции? я так понимаю что это в twisted тоже возможно?



Офлайн

#4 Май 10, 2010 12:40:20

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

[Twisted][Source][?] Как работает именно deffered?

    d = threads.deferToThread(dummyfunc)
d.addCallback(OnCalcCallback)



Офлайн

#5 Май 10, 2010 13:29:51

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

[Twisted][Source][?] Как работает именно deffered?

Это очевидно, ответ должен быть сложнее, но я пока не закончил его формулировку :-).

..bw



Офлайн

#6 Май 10, 2010 13:54:22

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

[Twisted][Source][?] Как работает именно deffered?

я только недавно начал смотреть на твистед, сложнее сказать не могу) Такой вопрос, в документации есть раздел как писать серверы:
http://twistedmatrix.com/documents/current/core/howto/servers.html
Вот если реализовывать такой простой сервер по документации, каким образом будет идти обработка запроса внутри твистед? Насколько я представляю это будет последовательная обработка запроса, те если один тяжелый запрос выполняется остальные маленькие ждут, те не распаралеливается обработка, тк там один поток работает.. верно ли это? и как можно тогда сделать их выполнение параллельно на твистед и можно ли?)



Офлайн

#7 Май 10, 2010 21:34:06

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

[Twisted][Source][?] Как работает именно deffered?

Во первых, кроме deferToThread есть еще процессы, последовательные порты и прочее.
Если handle можно переключить в non blocking mode - то можно и создать twisted transport для него. Без особыс проблем.

Да, в twisted работает один главный поток. Плюс один или несколько ThreadPool. Можно создать еще что-нибудь, но не предстваляю зачем.
Один тяжедый запрос разваливается на много маленьких deferred, между которыми вполне может проскочить несколько легковесных запросов.

Кстати, а для чего выполнять “параллельно”? И что означает “праллельно”?



Офлайн

#8 Май 11, 2010 03:25:32

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

[Twisted][Source][?] Как работает именно deffered?

Паралельно я имею ввиду создавать например поток для вычисления результат запроса.. чтобы один не блокировал остальные
Просто я почитал вот тут как работает реактор http://stackoverflow.com/questions/80617/asychronous-programming-in-python-twisted/81456
И судя по всему он достает последовательно вызовы которые зарегистрированы (коллбэки) и запускает, те судя по этому коду если вызов (коллбэк) который он запускает тяжелый, то следующие вызовы не смогут быть запущены пока он не посчитается .. Хотя могут прийти уже запросы и ждать обработки. Те чтобы получить паралельность обработки я внутри коллбэка сам должен вынести расчеты в отдельный поток например, так?



Офлайн

#9 Май 13, 2010 11:01:06

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

[Twisted][Source][?] Как работает именно deffered?

Уважаемый Evg.
Видимо, вы не вполне понимете работу реактивных систем.

Давайте сначала.
Есть фабрика->протокол->транспорт.
Протокол - основа общения. Один протокол на соединение.
Фабрика создает протоколы. TCP сервер создает протокол на каждое соединение, которых может быть много.
Транспорт - абстракция дескриптора, работающего в неблокирующем режиме. Сокет (кстати, у них много разновидностей - и много классов реализации) - только один из видов дескриптора. Существуют еще и такие как последовательный порт или inotify - система извещений об изменениях файловой системы.
Реактор на первых порах вообще как-бы в стороне. Он обеспечивает работу всей машинерии и светит наружу фабричные методы: сделать сокет такой-то, вызвать код через надцать секунд.
Обратите внимание: deferred в этой схеме пока что вообще отсутствуют.

Для сложных систем (считайте - практически для всего) создают протоколы второго уровня. Например, в случае с HTTP сервером вы будете работать с Resource, имея http request с уже подготовленными заголовками - и ответ тоже не опускается до байтов - устанавливаются нужные заголовки и заполняется тело. Возможно, не за один раз.

Теперь о “тяжелых запросах”. Тяжесть - она бывает разная. Одно дело, когда нужно много считать - и тогда выручает deferToThread. Вообще-то это случается редко. Гораздо чаще имеем другую ситуацию: чтобы ответить, нам нужно сначала спросить кого-то еще. Базу данных, другой сетевой ресурс и т.д.
Так вот, мы спрашиваем и в ответ получаем deferred. Сами в таком случае говорим “еще не готово” (чаще всего тоже возвращая deferred, в twisted.web нужно ответить NOT_DONE_YET). Реактор переключается на следующую задачу. Когда данные прийдут - сработает callback, мы их быстро обработаем в главном потоке (процессоры нынче ух как быстрые) - и наконец-то вернем ответ ожидающему концу соединения. Или запустим новый запрос и станем ждать его - опять освободив реактор.

Хорошо, если наши внутренние запросы поддерживают неблокирующие операции. Технически для этого нужно иметь нечто, что можно засунуть в select, poll и т.д. Иногда такое невозможно, потому что имеющийся интерфейс может работать только в блокирующем режиме (подавляющее большинство баз данных, например). В таком случае опять же делаем deferToThread и ждем. В отдельный поток лучше выносить только этот blocking call. Сейчас объясню почему.

На моей текущей работе нужно взаимодействовать с libvirt - эта такая либа для управления виртуальными машинами. Интерфейс - сугубо блокирующий.
Первая реализация мешала все в кучу: когда deferToThread а когда и просто вызов. В результате было не очевидно, исполняется ли метод в потоке реактора или мы уже в thread pool. Поскольку все отследить “в голове” было очень тяжело, иногда цепочка исполнения уводила на блокирующий вызов из главного потока. И все затыкалось.

Следующий естественный шаг - декомпозиция. Написали пару-тройку классов-оберток. Вызов каждого метода делал deferToThread, оборачивая блокирующий код и возвращая deferred. Обертки были тривиальные, а весь остальной код стал уверенно вращаться в реакторе. Проблема исчезла.

Я достаточно хорошо описал “параллельность” в том смысле, в котором ее понимают реактивные системы?
Кстати, если заменить twisted на GUI с событиями - суть почти не меняется.



Офлайн

#10 Май 13, 2010 13:53:22

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

[Twisted][Source][?] Как работает именно deffered?

Да, спасибо за развернутый ответ)
У меня вопрос насчет этого:

Андрей Светлов
Хорошо, если наши внутренние запросы поддерживают неблокирующие операции. Технически для этого нужно иметь нечто, что можно засунуть в select, poll и т.д. Иногда такое невозможно, потому что имеющийся интерфейс может работать только в блокирующем режиме (подавляющее большинство баз данных, например). В таком случае опять же делаем deferToThread и ждем. В отдельный поток лучше выносить только этот blocking call. Сейчас объясню почему.
Вот взять к примеру mysql, интерфейс же идет к нему через те же сокеты, те можно через не блокирующие сокеты с ним работать - т.е в этом плане не блокируется выполнение. Вот пришло например 5 запросов по чтению на сам mysql,я чесно говоря не в курсе таких деталей, но он теоретически может их выполнять в 5 потоках.. те получается что всеже интерфейс не блокирующий? Или же там все жестко блокируется и запросы строго по порядку пришедшие выполняются, в этом плане имеется ввиду?



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version