我使用win10和python 3.7.3 32位
我试图实现以下目标:每秒执行一次数据读出并打印,同时控制循环等待用户输入来控制设备。查看我的代码:
import device
import threading
from threading import Lock
def print_data(t_start):
while True:
data=getData() # generic example
print(f'data: {data} at time {time.time()-t_start}')
def control_func():
while True:
in_ = input(' Press ENTER to switch ON, Press x to quit')
if in_ == '':
device.on()
print('device ON')
elif in_ == 'x' or in_ == 'X':
device.off()
sys.exit()
else: continue
in_ = input(' Press ENTER to switch OFF, Press x to quit')
if in_ == '':
device.off()
print('device OFF')
elif in_ == 'x' or in_ == 'X':
device.off()
sys.exit()
else: continue
t_start = time.time()
device=device()
trd1 = threading.Thread(target=control_func())
trd2 = threading.Thread(target=print_data(t_start))
trd1.start() # starting the thread 1
trd2.start() # starting the thread 2
trd1.join()
trd2.join()
这只给我control_func()
的输入语句或print_data()
的打印
与使用多处理相同。我没能让这两个函数同时运行。
替换print()
s_print_lock = Lock()
# Define a function to call print with the Lock
def s_print(*a, **b):
"""Thread safe print function"""
with s_print_lock:
print(*a, **b)
也不起作用。既然我是新手,请帮帮我。或者我应该采用不同的方法?
您在创建Thread
的过程中调用了函数,您没有将函数传递给Thread
以使其执行,因此线程中没有发生实际的工作。修改Thread
创建为:
trd1 = threading.Thread(target=control_func) # Remove call parens
trd2 = threading.Thread(target=print_data, args=(t_start,)) # Remove call parens and pass args tuple separately
所以函数本身被传递,Thread
实际上在单独的逻辑执行线程中运行它们。如前所述,您运行control_func
至完成,然后运行print_data
至完成,然后启动两个Thread
,target=None
(两个函数的返回值)不做任何事情,然后join
和Thread
不做任何事情。
其他说明:
- 如果您正在使用
multiprocessing
,请确保使用multiprocessing.Lock
,而不是threading.Lock
(后者仅保证在单个进程中工作) - 虽然线程情况可能不需要锁(至少在GIL保护防止问题的CPython上),如果你一次只打印一个原子的东西,对于
multiprocessing
,你绝对应该使用锁并将flush=True
添加到所有print
;如果没有flush=True
,实际输出可能会无限期延迟。 - 你需要提供一些方法来传达循环已经完成到
print_data
;如前所述,control_func
将返回sys.exit()
,但这只退出线程,而不退出程序。除非getData
因为control_func
退出而抛出异常,否则print_data
永远不会退出,因此主线程也不会退出。
#3的解决方案包括:
- 使用
threading.Event()
;创建一个全局should_stop = threading.Event()
,将print_data
循环更改为while not should_stop.is_set():
,并在trd1.join()
返回后,让主线程调用should_stop.set()
- 将
trd2
设置为daemon
线程,并且不必费心join
它(假设它可以在trd1
和主线程结束时立即死亡);可能不适用于您的场景);当所有非daemon
线程退出时,它将强制死亡。