Python使用进程间共享变量来控制两个进程(监听键盘和相机录制)的交互

我有个简单的应用需求:

1. 该应用随时会监听键盘的输入;

2. 当输入指定键时会控制相机录制的启动和关闭。

监听键盘是一个事件循环,相机录制也是一个循环录制的过程。我试着用 Python 启动两个进程,并用两个进程共享变量的更新来控制两个进程的交互。

监听键盘输入

首先我找到python 监听键盘输入的方案可以满足我监听键盘的需求。

 1 import sys, select, tty, termios
 2 
 3 old_attr = termios.tcgetattr(sys.stdin) 
 4 tty.setcbreak(sys.stdin.fileno())   
 5 print('Please input keys, press Ctrl + C to quit')
 6 
 7 while(1):
 8     if select.select([sys.stdin], [], [], 0)[0] == [sys.stdin]:
 9         print(sys.stdin.read(1))
10 
11 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attr)

这段代码可以进行键盘监听,但是却有一个潜在 Bug第 11 行的代码永远无法执行,即使加上跳出循环的判断,当使用 Ctrl+C 时程序会终止。

而第 11 行的作用是恢复当前终端的原始属性,没执行到该语句,终端会变得不正常:你会发现程序结束后在该终端输入字符不会有显示。因此,程序应该设法程序终止时必然执行该语句

我建议改为类似的代码来修复这个 Bug:

 1 import sys
 2 import select
 3 import tty
 4 import termios
 5 
 6 old_attr = termios.tcgetattr(sys.stdin)
 7 tty.setcbreak(sys.stdin.fileno())
 8 print('Please input keys, press Ctrl + C to quit')
 9 
10 try:
11     while True:
12         if select.select([sys.stdin], [], [], 0)[0] == [sys.stdin]:
13             key = sys.stdin.read(1)
14             if key == 'q':
15                 # to stop the infinite loop
16                 break
17             elif key == 's':
18                 # do something
19                 print('I will do something')
20             else:
21                 # do other things
22                 print(key)
23 
24 except Exception as e:
25     print(e)
26 finally:
27     termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attr)

相机录制

相机录制的路径当然因不同的相机而异,因此这里我只写 Demo 级别的抽象代码:

 1 import time
 2 
 3 
 4 class Recorder:
 5     def __init__(self):
 6         print('Recorder initialization.')
 7 
 8     def run(self):
 9         time.sleep(0.3)
10         print('Recording a frame.')
11 
12     def close(self):
13         print('Recording ended.')
14 
15 
16 recorder = Recorder()
17 
18 t0 = time.time()
19 while time.time() - t0 < 10:
20     recorder.run()
21 
22 recorder.close()

可以看到这段逻辑也有一个条件循环。

假设应用的需求是按键 s,进行录制;再次按键 s,终止录制。

由于这两个逻辑需要完全同时进行,而 Python 的线程又是伪并行,因此这里考虑用多进程共享变量的通信。

使用进程间共享变量

使用 multiprocessing,直接看完整的代码是比较直观的:

 1 import time
 2 import sys
 3 import select
 4 import tty
 5 import termios
 6 import multiprocessing
 7 
 8 
 9 class Recorder:
10     def __init__(self):
11         print('Recorder initialization.')
12 
13     def run(self):
14         time.sleep(0.3)
15         print('Recording a frame.')
16 
17     def close(self):
18         print('Recording ended.')
19 
20 
21 def recording_process(shared):
22     recorder = Recorder()
23     while shared['is_recording']:
24         recorder.run()
25 
26     recorder.close()
27 
28 
29 if __name__ == '__main__':
30     # set shared variable
31     manager = multiprocessing.Manager()
32     shared = manager.dict()
33     shared['is_recording'] = False
34 
35     old_attr = termios.tcgetattr(sys.stdin)
36     tty.setcbreak(sys.stdin.fileno())
37     print('Please input keys, press Ctrl + C to quit')
38 
39     # check the keyborad
40     p = None
41     try:
42         while True:
43             if select.select([sys.stdin], [], [], 0)[0] == [sys.stdin]:
44                 key = sys.stdin.read(1)
45                 if key == 'q':
46                     # to stop the infinite loop
47                     break
48                 elif key == 's':
49                     # toggle
50                     shared['is_recording'] = not shared['is_recording']
51                     # resume or stop recording
52                     if shared['is_recording']:
53                         p = multiprocessing.Process(target=recording_process, args=(shared,))
54                         p.start()
55                     else:
56                         p and p.join()
57                 else:
58                     # do other things
59                     print(key)
60 
61     except Exception as e:
62         print(e)
63     finally:
64         termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attr)

原文作者:雨先生
原文链接:https://www.cnblogs.com/noluye/p/11704982.html  
许可协议:知识共享署名-非商业性使用 4.0 国际许可协议

参考

原文地址:https://www.cnblogs.com/noluye/p/11704982.html