в Python
Игорь Кальницкий
Время |
Задача А |
Задача Б |
Задача В |
---|---|---|---|
t + 0 |
исполняется |
– |
– |
t + 1 |
– |
исполняется |
– |
t + 2 |
– |
– |
исполняется |
t + 3 |
– |
исполняется |
– |
t + 4 |
– |
– |
исполняется |
t + 5 |
исполняется |
– |
– |
2 вычислителя
Время |
Задача А |
Задача Б |
Задача В |
---|---|---|---|
t + 0 |
исполняется |
исполняется |
– |
t + 1 |
исполняется |
– |
исполняется |
t + 2 |
– |
исполняется |
исполняется |
t + 3 |
исполняется |
исполняется |
– |
t + 4 |
– |
исполнятеся |
исполняется |
t + 5 |
исполняется |
– |
– |
from threading import Thread def sqr(x): return x * x Thread(target=sqr, args=(42, )).start()
from concurrent.futures import ThreadPoolExecutor def sqr(x): return x * x with ThreadPoolExecutor(max_workers=3) as executor: result = list(executor.map(sqr, [1, 2, 3, 4, 5]))
from concurrent.futures import ThreadPoolExecutor def sqr(x): return x * x with ThreadPoolExecutor(max_workers=3) as executor: result = list(executor.map(sqr, [1, 2, 3, 4, 5]))
import os os.fork()
Multiprocessing the Hard Way :)
from multiprocessing import Process def sqr(x): return x * x Process(target=sqr, args=(42, )).start()
from concurrent.futures import ProcessPoolExecutor def sqr(x): return x * x with ProcessPoolExecutor(max_workers=3) as executor: result = list(executor.map(sqr, [1, 2, 3, 4, 5]))
Характеристика |
Потоки |
Процессы |
---|---|---|
Ограничение GIL |
да |
нет |
Время создания |
меньше |
больше |
Время коммуникации |
меньше |
больше |
Потребление памяти |
меньше |
больше |
import eventlet; eventlet.monkey_patch() from threading import Thread def sqr(x): return x * x Thread(target=sqr, args=(42, )).start()
Зеленые потоки |
Потоки |
---|---|
Подходят только для I/O приложений. |
Подходят для любого рода приложений. |
Экономят системные ресурсы. |
Хотя и не будут исполняться параллельно. |
import asyncio async def sqr(x): return x * x loop = asyncio.get_event_loop() result = loop.run_until_complete(sqr(42))
Зеленые потоки |
asyncio |
---|---|
Совместимы с обычным многопоточным кодом. |
Требует использование специального синтаксиса, несовместимого с классическим кодом. |
Благодаря костылям, работают со многими библиотеками и драйверами к БД. |
Требует специальных версий библиотек и драйверов к БД. |
Существует мнение, что асинхронное программирование работает быстрее для I/O приложений за счет отсутствия необходимости переходить в kernel space для переключения между потоками.
from socket import * from threading import Thread def echo_server(conn): while True: data = conn.recv(100) if not data: break conn.send(data) s = socket(AF_INET, SOCK_STREAM) s.bind(('127.0.0.1', 5000)) s.listen(1000) while True: conn, addr = s.accept() Thread(target=echo_server, args=(conn, )).start()
import asyncio async def echo_server(reader, writer): while True: data = await reader.read(100) if not data: break writer.write(data) loop = asyncio.get_event_loop() coro = asyncio.start_server(echo_server, '127.0.0.1', 5000, loop=loop) server = loop.run_until_complete(coro) loop.run_forever()
Эхо-Сервер |
Кол-во клиентов |
Пропускная способность |
---|---|---|
на Потоках |
100 |
~ 130000 запросов/с |
на Корутинах |
100 |
~ 20000 запросов/с |
Эхо-Сервер |
CPU |
linux perf |
---|---|---|
на Потоках |
~ 195% |
|
на Корутинах |
~ 99% |
|
Эхо-Сервер |
Кол-во клиентов |
Пропускная способность на локальном хосте |
Пропускная способность в сети |
---|---|---|---|
на Потоках |
100 |
~ 130000 запросов/с |
~ 2800 запросов/с |
на Корутинах |
100 |
~ 20000 запросов/с |
~ 2800 запросов/с |