Оценить задержку Python для Python IPC - PullRequest
0 голосов
/ 21 сентября 2019

Для приложения Python мне нужно одновременно обрабатывать вывод дисплея OpenGL и последовательные выходы (например, для Arduino).Однако в идеале я хотел бы запускать различные виды выходов в отдельных процессах.

Поскольку дисплей и последовательный выход должны быть точно синхронизированы, я пытаюсь выяснить, насколько быстро происходит межпроцессное взаимодействие внутриPython (например, используя multiprocessing.Pipe).Но я столкнулся с проблемой, пытаясь сравнить это для данной аппаратной конфигурации.

Если я использую time.time(), чтобы оценить задержку IPC, она будет меньше 1us, что, на мой взгляд, слишком быстро.Когда я пытался использовать time.perf_counter() с другой стороны, я постоянно получал отрицательные задержки, что еще более странно.

Вот пример кода:

from multiprocessing import Pipe, Process, Event
import time

direct = False

timing_fun = time.time
#timing_fun = time.perf_counter

def p1(p1out, p2in, start):

    start.wait()
    print('Run p1 at %s' % str(timing_fun()))
    while True:
        print('Sending...')
        if not(direct):
            p1out.send(timing_fun())
        else:
            p2in.send(timing_fun())

        time.sleep(2.)

def p2(p2out, start):

    start.set()
    print('Run p2 at %s' % str(timing_fun()))
    while True:
        if p2out.poll():
            print('%.7f' % (timing_fun() - p2out.recv()))


def master():

    print('Start master')
    print('Running in %s mode' % ('direct' if direct else 'referred'))
    p1in, p1out = Pipe()
    p2in, p2out = Pipe()
    start = Event()

    process1 = Process(target=p1, args=(p1out, p2in, start))
    process1.start()

    process2 = Process(target=p2, args=(p2out, start))
    process2.start()


    print('Run main loop')
    while True:
        if p1in.poll():
            p2in.send(p1in.recv())


if __name__ == '__main__':

    master()

Запуск с time.time():

Start master
Running in referred mode
Run main loop
Run p2 at 1569056480.1104207
Run p1 at 1569056480.1104207
Sending...
0.0000000
Sending...
0.0000000
Sending...
0.0000000

Запуск с time.perf_counter():

Start master
Running in referred mode
Run main loop
Run p2 at 0.0628994
Run p1 at 0.0821299
Sending...
-0.0187006
Sending...
-0.0187737
Sending...
-0.0190505
Sending...
-0.0191084

Кто-нибудь знает разумный способ для сравнения задержки или есть какой-либо опыт относительно того, какую задержку я могу реально ожидать?

1 Ответ

0 голосов
/ 22 сентября 2019

После еще нескольких попыток я обнаружил, что, похоже, работает просто перенаправление сообщения обратно процессу, который его первоначально отправил, и использование time.perf_counter() для вычисления разницы:

from multiprocessing import Pipe, Process, Event
import time

timing_fun = time.perf_counter

def p1(p1out, p2in, start):

    start.wait()
    print('Run p1 at %s' % str(timing_fun()))
    while True:
        if p1out.poll(timeout=0.1):
            print('%.7f' % (timing_fun() - p1out.recv()))

        time.sleep(2.)

        print('Sending...')
        p2in.send(timing_fun())


def p2(p2out, p1in, start):

    start.set()
    print('Run p2 at %s' % str(timing_fun()))
    while True:
        if p2out.poll():
            msg = p2out.recv()
            p1in.send(msg)


def master():

    print('Start master')
    p1in, p1out = Pipe()
    p2in, p2out = Pipe()
    start = Event()

    process1 = Process(target=p1, args=(p1out, p2in, start))
    process1.start()

    process2 = Process(target=p2, args=(p2out, p1in, start))
    process2.start()

if __name__ == '__main__':

    master()

В соответствии сдокументация для time.perf_counter() эталонной точки должна быть общесистемной, поэтому я до сих пор не знаю, почему мой первоначальный подход не сработал, когда я вызвал его из двух отдельных процессов (может быть, у кого-то есть ответ на этот вопрос?).Но, по крайней мере, вышеприведенное решение работает, потому что оно устанавливает задержку двусторонней связи Pipes чуть ниже 1 мс, что кажется разумным (базовая скорость i9-9820X@3.3GHz):

Start master
Run p2 at 0.0653889
Run p1 at 0.0928306
Sending...
0.0004457
Sending...
0.0003819
Sending...
0.0006137
Sending...
0.0005876
Sending...
0.0005943
...