Comments 36
В задачах где нужно много CPU и мало I\O — выбираем потокиА вы точно про Python говорите?
А как потоками можно загрузить несколько ядер одновременно, если GIL не дает выполняться больше чем одному потоку в один момент времени?
Ещё раз простите за кривизну изложения мысли
Он посложнее в разработке и отладке.
А еще есть уйма полезных блокирующих библиотек.
Например, для POSIX select:
File descriptors associated with regular files shall always select true for ready to read, ready to write, and error conditions.Так что реквестирую у вас работающий пример с чтением/записью обычного файла на диске через asyncio (без использования тред-пулов, конечно).
Можно использовать aio_read().
import asyncio
import selectors
import os
devnull = os.open("/dev/null", os.O_RDONLY)
def reader():
data = os.read(devnull, 50)
print("Successfully read {} bytes from /dev/null".format(len(data)))
loop = asyncio.SelectorEventLoop(selectors.SelectSelector())
loop.add_reader(devnull, reader, )
loop.run_forever()
Скрипт бесконечно печатает «Successfully read 0 bytes from /dev/null».
С epoll будет ошибка при вызове 'add_reader'.
import asyncio
import selectors
import os
path = "/etc/fstab"
f = os.open(path, os.O_RDONLY)
def reader():
data = os.read(f, 50)
print("Successfully read {} bytes from {}".format(len(data), path))
print("data: {}".format(data))
loop = asyncio.SelectorEventLoop(selectors.KqueueSelector())
loop.add_reader(f, reader, )
loop.run_forever()
Вывод:
Successfully read 50 bytes from /etc/fstab
data: b'# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#\n/d'
Successfully read 50 bytes from /etc/fstab
data: b'ev/ada0p2\t\tnone\tswap\tsw\t\t0\t0\n/dev/ada1p2 '
Successfully read 50 bytes from /etc/fstab
data: b' none swap sw 0 0\nlinpr'
Successfully read 50 bytes from /etc/fstab
data: b'oc /compat/linux/proc linprocfs rw 0 0\nfdesc /dev/'
Successfully read 50 bytes from /etc/fstab
data: b'fd fdescfs rw 0 0\ntmpfs /compat/linux/dev/shm'
Successfully read 24 bytes from /etc/fstab
data: b'\ttmpfs\trw,mode=1777\t0\t0\n'
Искренне полагал, что и epoll поддерживает, оказывается таки нет. Но все равно вывод — однозначно сказать да или нет нельзя, зависит от ОС.
Не со всеми определениями автора я согласен.
В синхронных операциях задачи выполняются друг за другом.
В данном случае не совсем удачное слово "задачи". Задачи могут быть вполне себе асинхронными, например пул обработчиков http запосов, но каждый из них может работать синхронно, тоесть последовательно: обработал параметры запроса, подготовил данные, передал ответ.
В асинхронных задачи могут запускаться и завершаться независимо друг от друга.
Правильнее говорить: в программе прописаны критерии, когда стартует асинхронная задача, но не время. Асинхронная задача может вообще не вызываться, или вызываться очень часто и исполняться, как в синхронном, так и асинхронном режиме. Простой пример: программа выполняет какую — то долгоиграющую операцию, и способна реагировать на Ctrl+C, нажмет оператор на эти кнопки или нет, нажмет, но потом передумает, и позволит программе продолжаться, или прервет ее, это зависит от оператора, но не от программы.
Конкурентность подразумевает, что две задачи выполняются совместно
Конкурентность подразумевает, что 2 задачи совместно используют одни и те же данные. Способ исполнения самих задач здесь не столь важен.
Параллелизм по сути является формой конкурентности.
Конкурентный доступ к данным является следствием появления возможности для паралельного исполнения кода.
Но параллелизм зависит от оборудования. Например, если в CPU только одно ядро, то две задачи не могут выполняться параллельно.
Да, 95 форточки, со своей кооперативной многозадачностью устарели, но они были, и для своего времени весьма не плохо справлялись.
Python поддерживает потоки уже очень давно. Потоки позволяют выполнять операции конкурентно.
Ядерные потоки в питоне — это скорее повод для головной боли разрабов, поэтому их не особо и используют. Байткод питона не атомарен, сам питон использует потоки для своих нужд, на сколько я помню, и поэтому у питона есть GIL, чтобы разраб ненароком чего нибудь не уронил, в процессе работы. А так, да, потоки в питоне есть.
По поводу async/await и asyncio, это не что иное, как синтаксический сахар над реализацией кооперативной многозадачности на одном потоке исполнения. Если вы много читаете по сети, или с диска, да, вы можете это использовать, и получить профит по количеству обработанных задач, но, например, на вычислительных задачах выигрыша не будет.
Для CPU зависимых задач интерпретатор делает проверку каждые N тиков и переключает потоки.
Насколько мне известно, с версии Python 3.2 используются не тики, а миллисекунды.
Асинхронный Python: различные формы конкурентности