Как избежать блокировки кода в python с помощью gevent?

Я играю с gevent, и я пытаюсь понять, почему мой код блокирует и как я могу это исправить.

У меня есть пул зеленых, и каждый из них разговаривает с бережливым клиентом, который собирает данные с удаленного бережливого сервера. Для целей упражнения бережливый сервер всегда принимает > 1s для возврата любых данных. Когда я создаю зелья и запускаю соединение, они не выполняют все параллельно, а вместо этого один за другим. Я понимаю, что это происходит из-за того, что мой код "блокируется", поскольку, когда я запускаю monkey.patch_all(), все зеленые панели волшебным образом запускаются параллельно.

Итак, как мне заставить код не блокировать себя, а не обезвреживать все и не понимать, что он делает?

Вот пример того, что я не понимаю:

import time

from gevent.pool import Pool

def hello():
    print 'Hello %d' % time.time()
    time.sleep(1) 

def main():
    pool = Pool(5)
    for _ in xrange(5):
        pool.spawn(hello)

    pool.join()

if __name__ == '__main__':
    main()

Выход

Hello 1345477112
Hello 1345477113
Hello 1345477114
Hello 1345477115
Hello 1345477116

Я знаю, что могу использовать gevent.sleep, но как сделать эту функцию не блокирующей с регулярным time.sleep?

Спасибо

Ответ 1

Гринлеты никогда не запускаются параллельно, все они имеют один и тот же процесс и один и тот же поток, поэтому в нем работает не более одного из них.

Зеленые зеленые, потому что они являются совместными подпрограммами ( "co" от сотрудничества), поэтому нельзя даже сказать, что они работают одновременно, потому что вам нужно координировать их работу. Gevent делает большую часть этой работы для вас за кулисами и знает из libevent (или libevent), какие зеленые наборы готовы к запуску. Преобладания вообще нет.

В примере, который вы указали, time.sleep(2) переведет процесс в операционную систему, поэтому планировщик gevent не будет запущен и не сможет переключиться на другую родословную.

Итак, в отношении вашего вопроса: если вы не хотите, чтобы обезьяна исправляла существующий код, вам придется вручную заменить каждый блокирующий вызов эквивалентом gevent, чтобы gevent мог отложить вызов зеленой очереди и выбрать другой работать.

РЕДАКТОР: Что касается использования gevent с бережливостью без обезьянья патчей все: я не знаю, стоит ли это.

Если вы хотите изменить (fork) бережливую библиотеку, просто нужно изменить файл TSocket.py и изменить:

import socket

в

from gevent import socket

Но тогда ваша бережливая библиотека будет зависеть от gevent, и вам нужно будет повторно использовать патч, если вы когда-нибудь обновите бережливость.

Вы также можете подклассифицировать TSocket, изменить метод open() на использование gevent socket и использовать его вместо первого, но мне кажется более сложным.

Я фактически использую Thrift с Gevent, и я выбираю для обезьяны, исправляя все это ради простоты.