Как в питоне запустить параллельно функцию в 2020 году?
хотел бы знать как в 2020году правильно запускать задачу в python3+ параллельно?
Задача имеется ввиду функция, которая будет исполняться на отдельной нити параллельно(т.е. multiprocessing не подходит).
Честно говоря, в интернете кроме как вызвать Thread и запустить его демоном(так я и делаю сейчас), больше ничего толкового не находится. Но кажется мне, что все-таки так делать это слишком ретроградно. Нагуглил тут pykka, и создание актора примерно так:
class Adder(pykka.ThreadingActor):
def add_one(self, i):
print(f'{self} is increasing {i}')
return i + 1
Но опять же не хватает квалификации понять: будет ли это выполняться параллельно? В Python я новичек совсем, помогите... Может это совсем невозможно т.к. GIL и т.д.
Можно свести задачу к следующему: в одном потоке делать кое-что, в другое потоке по таймеру, вызывать еще одну функцию - в ней посылать rpc-запросы:
ПОТОК 1: блокирующая функция
ПОТОК 2: по таймеру вызываем rpc_send()
Ответы (1 шт):
call_later, call_at, call_soon и тд выполняется в основном потоке
import asyncio
loop = asyncio.get_event_loop()
def timer(loop):
loop.call_later(1, timer, loop)
print('тыц')
timer(loop) # первый тыц сразу
loop.run_forever()
loop.run_forever() - блокирует, так что остальной код надо писать также на тасках asyncio.
В этом примере таймер следующий тыц выполнится через секунду, но после слова await в основном коде или при запуске любой операции на loop. Если других задач нет - то выполнится по таймеру.
По условиям задачи есть блокирующая функция - лучше переделать её на неблокирующий вариант. Асинкио предоставляет возможности для любого IO сделать асинхронный код.
Если сделать это не удается, то блокирующий кусок выносится в тред
import asyncio
loop = asyncio.get_event_loop()
def blocking_code():
time.sleep(1000)
def timer(loop):
loop.call_later(1, timer, loop)
print('тыц')
timer(loop) # первый тыц сразу
task = loop.create_task(loop.run_in_executor(
None, blocking_code))
loop.run_forever()
При этом GIL ещё работает. Обычно это не проблема, но можно его обойти через процессы
pool = concurrent.futures.ProcessPoolExecutor()
... loop.run_in_executor(pool, blocking_code) ...
P.S. Никогда не выполняйте блокирующий код в основном потоке хотябы потому что "программа не отвечает, завершить процесс?"