Python Gevent в функции, которая не исправляется - PullRequest
0 голосов
/ 03 мая 2018

Я работаю в REST-сервисе, который по сути является оберткой для библиотеки. Я использую флягу и огнестрельное оружие. По сути, каждая конечная точка в службе отображается на другую функцию в библиотеке.

Бывает, что для некоторых вызовов в библиотеку может потребоваться много времени, и из-за этого у моей службы заканчиваются рабочие, когда служба начинает получать несколько запросов. Прямо сейчас я использую рабочих-оружейников по умолчанию (синхронизация).

Я хотел использовать работников gevent, чтобы иметь возможность получать больше запросов, потому что не каждая конечная точка требует столько времени для выполнения. Однако функция в библиотеке не использует ни одну из исправляемых функций gevent, что означает, что она не будет совместно планировать другой зеленый поток.

У меня была идея использовать пул потоков или процессов для асинхронной обработки вызовов библиотеки, а затем каждый зеленый поток, созданный gunicorn, будет бездействовать, пока процесс не завершится. Эта идея имеет смысл вообще?

Можно ли использовать мультипроцессинг. Процесс с gevent? а затем есть метод соединения, чтобы передать управление другому зеленому потоку, и возвращать только после завершения процесса?

1 Ответ

0 голосов
/ 03 мая 2018

Да, имеет смысл использовать (реальные) потоки или процессы из gevent для кода, который должен быть асинхронным, но не может быть обезличен gevent.

Конечно, может быть сложно получить правильные результаты - во-первых, потому что вы, возможно, запатентовали threading, а во-вторых, потому что вы хотите, чтобы ваши кооперативные потоки могли блокировать пул или результат пула, не блокируя весь основной нить.

Но это именно то, для чего gevent.threadpool.

Если бы вы использовали concurrent.futures.ThreadPoolExecutor в приложении, отличном от gevent, monkeypatch threading, а затем используйте gevent.threadpool.ThreadPoolExecutor.

Если бы вы использовали multiprocessing.dummy.Pool в приложении, отличном от gevent, monkeypatch threading, а затем используйте gevent.threadpool.ThreadPool.

В любом случае, такие методы, как map, submit, apply_async и т. Д., Работают почти так, как вы ожидаете. Объекты Future и AsyncResult хорошо играют с гринлетами; Вы можете gevent.wait вещей, или прикрепить обратные вызовы (которые будут работать как гринлеты) и т. д. В большинстве случаев это просто работает как магия, а в остальное время это не слишком сложно выяснить.


Использование процессов вместо потоков выполнимо, но не так хорошо. AFAIK, нет обёрток для чего-то такого полного, как multiprocessing.Process или multiprocessing.Pool, и попытка использовать обычный multiprocessing просто зависает. Вы можете вручную fork, если вы не работаете в Windows, но это все, что встроено. Если вам действительно нужна многопроцессорная обработка, вам может потребоваться выполнить многослойную работу, когда ваши гринлеты не будут работать. не разговаривать с процессом, а вместо этого общаться с потоком, который создает канал, вилки, execs, а затем прокси между миром gevent и дочерним процессом.

Если вызовы занимают много времени, потому что они ожидают ввода-вывода от бэкэнд-службы, или ожидают на подпроцессе, или выполняют неповоротливую работу по GIL-выпуску, я бы не стал пытаться делать multiprocessing , Но если они отнимают много времени из-за того, что загружают процессор… ну, тогда вам нужно либо заставить многопроцессорную работу работать, либо перейти на более низкий уровень и просто выделить subprocess.Popen([sys.executable, 'workerscript.py']).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...