Есть ли способ засыпать с интервалом в миллисекунды с помощью асинхронного сна?
В Linux asyncio использует системный вызов epoll_wait
, который указывает время ожидания в миллисекундах,поэтому любая миллисекунда не будет работать, несмотря на то, что она может быть указана в asyncio.sleep()
.
. Вы можете проверить это на своем компьютере, запустив следующую программу:
import asyncio, os
SLEEP_DURATION = 5e-3 # 5 ms sleep
async def main():
while True:
# suspend execution
await asyncio.sleep(SLEEP_DURATION)
# execute a syscall visible in strace output
os.stat('/tmp')
asyncio.run(main())
Сохранитьнапример, как sleep1.py
и запустите ее под strace
, например:
$ strace -fo trc -T python3.7 sleep1.py
<wait a second or two, then press Ctrl-C to interrupt>
Файл trc
будет содержать достаточно точные временные интервалы того, что происходит под капотом.После последовательности запуска Python программа в основном выполняет следующие действия в бесконечном цикле:
24015 getpid() = 24015 <0.000010>
24015 epoll_wait(3, [], 1, 5) = 0 <0.005071>
24015 epoll_wait(3, [], 1, 0) = 0 <0.000010>
24015 stat("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=45056, ...}) = 0 <0.000014>
Мы видим вызов getpid()
, два вызова epoll_wait
и, наконец, вызов stat
,Первый epoll_wait
действительно актуален, он указывает время ожидания в миллисекундах и спит приблизительно в течение требуемого периода.Если мы снизим длительность сна до миллисекунд, например, 100e-6, strace
покажет, что asyncio по-прежнему запрашивает тайм-аут в 1 мс от epoll_wait
и получает столько же.То же самое происходит с таймаутами до 15 минут.Если вы укажете тайм-аут 14 или менее, asyncio фактически запрашивает опрос без тайм-аута, а epoll_wait
завершается через 8 секунд.Тем не менее, вторая epoll_wait
также отнимает 8 у нас, поэтому вы не можете рассчитывать на микросекундное разрешение в любой форме.
Даже если вы используете потоки и занятый цикл, вы, скорее всего, столкнетесь с синхронизациейпроблемы с GIL.Вероятно, это следует делать на языке более низкого уровня, таком как C ++ или Rust, и даже в этом случае вам нужно быть осторожным с планировщиком ОС.