asyncio: сон в течение миллисекундного интервала - PullRequest
0 голосов
/ 02 февраля 2019

Я строю устройство на основе малинового пи.Он будет иметь несколько одновременных функций, которые должны работать одновременно.В этом случае использование asyncio выглядит разумным выбором (ну, я могу написать все это на C ++ с потоками, но код на python выглядит намного компактнее)

Одна из функций - управлять шаговым двигателем через GPIO.импульсы.Эти импульсы должны быть длиной 5-10 микросекунд.Есть ли способ засыпать с интервалом менее миллисекунды с помощью асинхронного сна?

1 Ответ

0 голосов
/ 03 февраля 2019

Есть ли способ засыпать с интервалом в миллисекунды с помощью асинхронного сна?

В 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, и даже в этом случае вам нужно быть осторожным с планировщиком ОС.

...