简体   繁体   中英

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

I'm running a Python script that controls a robot, but I'm a bit confounded as to how to multithread the motor control function.

The issue is that the hardware is designed such that the motors won't move unless there are several sleeps in the motor-control function, because the hardware requires time to send the electrical signals to the motors. Because of these sleeps in the motor-control function, the entire program halts and stops reading in sensor data.

What I would like to do is know how to multithread/multiprocess the motor-control function once it is called, but once the program hits the call again in the following iteration of the loop, it checks if the motor-control is still running (ie it isn't done with the sleep). If it is still running, it simply skips over the motor-control call and continues on with looping, reading sensor data, and then checking again if the motor-control function is still running. Of course, if the motor-control function is no longer running, I would like for it to once again be called.

Basically, the whole program only requires two threads: one that runs the main program, and one that branches off and continuously re-runs one instance of the motor-control function every time the motor-control function has completed its execution.

I had tried using the concurrent.futures import but got messages saying it was not supported and I couldn't find any usages particular to the way I intend to use it.

I think you don't need threading, but I may misunderstand your requirements so I will present 2 alternatives.

  1. Without threading and sleeps

Assuming your current program flows like that :

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

Then you could just remove the sleep, and only call motor_do if the last call was at least delay seconds ago.

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. With threading (this is an example, I have no experience in threading/async with python 2.7 so there may be better ways to do this)

Assuming your current program flows like that :

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

Then you have to launch 1 thread that will only push the commands to the motor, asynchronously.

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)

NB : on Unix, time.clock() returns processor time (= without the idling time), so it would be better to use time.time() ... unless the system clock is changed : "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 doc)

I don't know how time.sleep() react to system clock changes.

see 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() can be useful)

Python3 : just use time.monotonic() ... or time.perf_counter() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM