как запустить событие на определенной частоте с python - PullRequest
1 голос
/ 12 апреля 2020

Я хотел бы запустить событие с определенной частотой, например, 44100 Гц.
Я ожидал бы, что приведенный ниже код будет выполнять «печать» 44100 раз в секунду, но это не так.

import time

frequency = 44100
desired_interval = 1 / frequency

events = 0

time_now = time.time()
time_end = time_now +1

while time_now < time_end:

    events += 1
    print(events)

    # some time has passed, sleep for desired interval less passed time
    if( desired_interval > ( time.time() - time_now ) ):
        time.sleep( desired_interval - ( time.time() - time_now ) )

    time_now = time.time()    

Ответы [ 2 ]

0 голосов
/ 12 апреля 2020

Чтобы понять, почему дела идут дольше, чем вы думаете, мы должны использовать profiler .

Сохраняя ваш код как timer.py, я запустил следующее:

python3 -m cProfile -s tottime timer.py

Результат был:

37621
37622
37623
37624
37625
37626
         188134 function calls in 1.000 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    37626    0.840    0.000    0.840    0.000 {built-in method time.sleep}
    37626    0.104    0.000    0.104    0.000 {built-in method builtins.print}
        1    0.045    0.045    1.000    1.000 timer.py:1(<module>)
   112879    0.012    0.000    0.012    0.000 {built-in method time.time}
        1    0.000    0.000    1.000    1.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Итак, на моей машине он работал 37626 раз в секунду. Большая часть этого времени тратится на выполнение time.sleep().

Дело в том, что при расчете задержки вы не учитываете время, необходимое для выполнения кода python. Также не учитывается, что Python выполняется поверх операционной системы, которая также запускает другие программы.

Давайте упростим программу до следующего:

import time

frequency = 44100
desired_interval = 1 / frequency * 0.72
events = 0
time_now = time.time()
time_end = time_now + 1
while time_now < time_end:
    events += 1
    print(events)
    time.sleep(desired_interval)
    time_now = time.time()

Вкл. моя система, это печатает примерно 44100 раз в секунду. Как видите, мне пришлось сократить время, затрачиваемое на сон, примерно на 30%, чтобы учесть накладные расходы. И это всего лишь игрушечная программа.

Глядя на желаемую частоту, кажется, что вы хотите выполнять качественную обработку аудио CD в режиме реального времени. Честно говоря, Python не может быть правильным выбором для этого.

Что вам нужно сделать, это обернуть реальную работу , которую вы хотите выполнить в функции, и запустить профилировщик на который. Результаты профилирования подскажут вам, сможете ли вы выполнить требуемую работу в нужное время.

Если вы не можете, есть несколько вариантов его ускорения;

  • Использование numpy.
  • Использование cython.
  • Использование pypy.
0 голосов
/ 12 апреля 2020

Это ближе, даже если наиболее вероятно (вполне уверен), что событие "print" не запускается с регулярной частотой.

import time

frequency = 44100
desired_interval = 1 / frequency

events = 0

time_now = time.time()
time_start = time_now
time_end = time_now +1

while time_now < time_end:

    events += 1
    print(events)

    if( desired_interval * events > ( time.time() - time_start ) ):
        # abs mitigate the fact that sometime the result is negative.
        time.sleep( abs( desired_interval * events - ( time.time() - time_start ) ) )


    time_now = time.time()
...