Поток не работает достаточно быстро, когда работают другие приложения - PullRequest
2 голосов
/ 19 апреля 2019

Я использую модуль потоков для запуска функции в фоновом режиме, в то время как остальная часть моего сценария выполняется. Потоковая функция содержит цикл for, который ожидает внешних 5-вольтных триггеров, возникающих каждые 15 мс, прежде чем перейти к следующей итерации цикла.

Когда этот код работает только на ПК, все работает как положено. Однако когда я запускаю другие необходимые приложения, нагружая процессор, цикл For в поточной функции выполняется только и продолжается до следующей итерации в течение 15 мс времени примерно в 90% времени.

Введением в многопоточную функцию является список указателей ctypes.

Я запускаю многопоточную функцию из класса, поэтому использование многопроцессорности сложно (если это вообще поможет, я не уверен).

Я попытался проиллюстрировать проблему ниже скелетом двух классов

import ctypes
import Write_transient_frames_func
import SendScriptCommands
from threading import Thread

class SlmInterface():

    def __init__(self,sdk):

        self.sdk = sdk

    def precalculate_masks(self, mask_list):

        '''takes input mask_list, a list of numpy arrays containing phase masks
           outputs pointers to memory location of masks
        '''

        #list of pointers to locations of phase mask arrays in memory 
        mask_pointers = [mask.ctypes.data_as(POINTER(c_ubyte)) for mask in mask_list]

        return mask_pointers

    def load_precalculated_triggered(self, mask_pointers):

        okay = True
        print('Ready to trigger')

        for arr in mask_pointers:

            okay = self.Write_transient_frames_func(self.sdk, c_int(1), arr, c_bool(1), c_bool(1), c_uint(0))

        assert okay, 'Failed to write frames to board'      
        print('completed trigger sequence')


class Experiment():

    def run_experiment(self, sdk, mask_list):  

        slm = SlmInterface(sdk)

        #list of ctypes pointers      
        mask_pointers = slm.precalculate_masks(mask_list)

        ##the threaded function
        slm_thread = Thread(target=slm.load_precalculated_triggered, args = [mask_pointers])
        slm_thread.start()

        time.sleep(0.1)

        # this function loads the 15ms trigger sequences to the hardware and begins the sequence 
        self.mp_output = SendScriptCommands()

Можно ли ускорить выполнение резьбовой функции? Поможет ли параллельная обработка? Или я принципиально ограничен моим процессором?

Ответы [ 3 ]

1 голос
/ 19 апреля 2019

Вы должны знать, что многопоточность в python замедляет работу приложения. Хорошей альтернативой является использование asyncio, потому что оно позволяет выполнять многозадачность нескольких задач в одном потоке (-> ОС не нужно фактически переключать поток -> меньше накладных расходов -> более быстрое выполнение). Если вы раньше этим не пользовались, сначала это надоело использовать, но на самом деле это действительно здорово.

Однако ваша задача действительно связана с процессором. Так что, возможно, единственным вариантом является многопроцессорность в Python.

1 голос
/ 19 апреля 2019

Вероятно, Python на самом деле не виновник. Дело в том, что в общем случае приоритетными являются многопользовательские операционные системы, которые вы не гарантируете, что они будут работать достаточно непрерывно, чтобы перехватывать триггеры в течение любых 15 мс. ЦП распределяется в виде квантов, обычно составляющих несколько десятков мс, и ОС может - и будет - позволять вашему потоку запускаться более или менее часто в зависимости от загрузки ЦП, чтобы выделить каждому процессу справедливую долю доступного времени ЦП.

Вы можете увеличить приоритет вашего потока, чтобы запросить его приоритет над остальными, или, в крайнем случае, изменить его на приоритет в реальном времени, чтобы он мог загружать процессор на неопределенное время (и потенциально зависать в системе). если что-то пойдет не так).

Но на самом деле, на самом деле решение состоит в том, чтобы обрабатывать это на более низком уровне, либо в режиме ядра, либо в аппаратном обеспечении. Опрос с такой скоростью из пользовательского режима нежелателен, если вы не можете пропустить сигнал, поэтому вам, вероятно, следует выяснить, обеспечивает ли ваше оборудование / драйвер какой-либо интерфейс более высокого уровня - например, прерывание (переводимое, например, для разблокировки какого-либо блокирующего вызова или подачи сигнала). или что-то) на триггере.

1 голос
/ 19 апреля 2019

К сожалению, Python, вероятно, не сможет работать намного лучше.Python имеет глобальную блокировку интерпретатора , что означает, что многопоточность работает не так, как в других языках.

...