如何 multithread/multiprocess 只是 Python 中特定函数的一个实例?

How to multithread/multiprocess just one instance of a particular function in Python?

我是 运行 一个 Python 控制机器人的脚本,但我对如何对电机控制函数进行多线程处理感到有点困惑。

问题是硬件的设计使得电机不会移动,除非在电机控制功能中有几次休眠,因为硬件需要时间将电信号发送到电机。由于电机控制功能中的这些休眠,整个程序暂停并停止读取传感器数据。

我想做的是知道如何 multithread/multiprocess 电机控制函数一旦被调用,但是一旦程序在接下来的循环迭代中再次调用,它会检查是否motor-control 仍然是 运行(即它没有在睡眠时完成)。如果它仍然是 运行,它只是跳过电机控制调用并继续循环,读取传感器数据,然后再次检查电机控制函数是否仍然是 运行。当然,如果电机控制功能不再运行,我希望它再次被调用。

基本上,整个程序只需要两个线程:一个运行主程序,另一个分支并在每次电机控制功能完成时不断重新运行电机控制功能的一个实例。执行。

我曾尝试使用 concurrent.futures 导入,但收到消息说它不受支持,而且我找不到任何特定于我打算使用它的方式的用法。

我认为您不需要线程,但我可能会误解您的要求,所以我将提供 2 个备选方案。

  1. 没有线程和睡眠

假设您当前的程序流程是这样的:

while True:
    data = read_sensors()
    command = process(data)
    motor_do(command)
    time.sleep(delay)

然后你可以取消睡眠,并且只在上次调用至少在 delay 秒前调用 motor_do。

last_call_time = -delay # to be sure that motor_do can be called the first time
# "On Windows, [time.clock] returns wall-clock seconds elapsed since the first call to this
# function, as a floating point number, based on the Win32 function QueryPerformanceCounter()
# The resolution is typically better than one microsecond." (python 2.7 doc)
# i.e. close to 0 on first call of time.clock()

while True:
    data = read_sensors()
    command = process(data)
    motor_try(command)

def motor_try(command):
    global last_call_time

    current_time = time.clock()
    # on win that works, on unix... you may want to take a look at the NB

    elapsed = current_time - last_call_time
    if elapsed >= delay:
        motor_do(command)
        last_call_time = current_time
  1. 使用线程(这是一个例子,我没有使用 threading/async 和 python 2.7 的经验,所以可能有更好的方法来做到这一点)

假设您当前的程序流程是这样的:

while True:
    data = read_sensors()
    command = process(data)
    motor_do(command) // this function sleeps and you CANNOT change it

然后你必须启动 1 个线程,它只会将命令异步推送到电机。

import thread

command = None
command_lock = thread.allocate_lock()

def main():
    thread.start_new_thread(motor_thread)

    global command
    while True:
        data = read_sensors()
        with command_lock:
            command = process(data)

def motor_thread():
    while True:
        while not command: # just to be sure
            time.sleep(0.01)
            # small delay here (for instance, the time consumed by read_sensors + process)
        with command_lock:
            motor_do(command)
            command = None
        time.sleep(delay)

注意:在 Unix 上,time.clock() returns 处理器时间(= 没有空闲时间),所以最好使用 time.time()... 除非系统时钟是已更改:"While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls."(python 2.7 文档)

我不知道 time.sleep() 如何对系统时钟变化做出反应。

参见 How do I get monotonic time durations in python? for precise time delays on unix/py2.7 (and Understanding time.perf_counter() and time.process_time() 可能有用)

Python3 :只需使用 time.monotonic()... 或 time.perf_counter().