問題描述
我遇到了多處理問題.如果我在線程中等待輸入,則進(jìn)程不會啟動.
I have a problem with multiprocessing. If I am waiting for input in a thread the process is not starting.
將輸入放入后臺隊列的類:
The class to put the input into a queue in the background:
class InputCatcher(Thread):
def __init__(self, input_queue):
Thread.__init__(self)
self.input_queue = input_queue
def run(self):
while True:
self.input_queue.put(input()) # <<-- Without this it works!
不會開始的類:
class Usb(Process):
def __init__(self, port, ctrl=Controller()):
Process.__init__(self)
self.usb_port = port
self.ctrl = ctrl
def run(self):
self.ctrl.usb_ports.append(self.usb_port)
ser = Serial(self.usb_port, 115200)
while True:
dsl = ser.readline()
self.ctrl.get_dataset_queue().put(['USBDS', dsl])
print(dsl)
開始于:
ic = InputCatcher(self.input_queue)
ic.setDaemon(True)
ic.start()
usbs = []
for port in usb_ports():
if not port in ctrl.xbee_ports:
usbs.append(Usb(port, ctrl))
for usb in usbs:
usb.daemon = True
usb.start()
推薦答案
當(dāng)你調(diào)用 input
時,它阻塞了整個 Python 進(jìn)程,而不僅僅是它運(yùn)行的線程.發(fā)生這種情況是因為從與從任何其他類似文件的對象中讀取一樣,STDIN 涉及進(jìn)行阻塞系統(tǒng)調(diào)用 - 即 input
阻塞以等待用戶輸入發(fā)生在操作系統(tǒng)級別,而不是在 Python 自己的線程管理代碼內(nèi)部.Python 線程對 OS 進(jìn)程調(diào)度程序本質(zhì)上是不可見的,因此 Python 本身 會被阻塞.
When you call input
, it is blocking the entire Python process, not just the thread it runs in. This happens because reading from STDIN, like reading from any other file-like object, involves making a blocking syscall - that is, input
blocking to wait for user input happens at the OS level, rather than inside Python's own thread management code. Python threads are essentially invisible to the OS process scheduler, so Python itself gets blocked.
解決此類阻塞問題的常用方法是使用進(jìn)程而不是線程.如果你把 InputCatcher 變成一個進(jìn)程而不是線程,那么它就變成了一個獨立的操作系統(tǒng)級進(jìn)程,操作系統(tǒng)可以獨立調(diào)度,因此系統(tǒng)調(diào)用只會阻塞 那個 進(jìn)程而不是主進(jìn)程.
The usual way around blocking problems like this is to use processes instead of threads. If you make InputCatcher into a process rather than a thread, then it becomes a separate OS-level process that the OS can schedule independently, and so the syscall will only block that process and not the main one.
除了,Python 會自動在您生成進(jìn)程時關(guān)閉 STDIN.
Except, that Python automatically closes STDIN when you spawn a process.
因此,您需要在主進(jìn)程中擁有隊列的生產(chǎn)者,而在另一個進(jìn)程中只有消費(fèi)者.這也是一個微不足道的適應(yīng) - 不要啟動生產(chǎn)者 (InputCatcher) 直到在所有消費(fèi)者進(jìn)程已經(jīng)產(chǎn)生之后運(yùn)行.這涉及到移動線路:
So, you would need to have the producer for the queue in the main process, and only the consumer in another one. This is also a trivial adaption - don't start the producer (InputCatcher) running until after all of the consumer processes have spawned. That involves moving the line:
ic.start()
到下面兩個循環(huán).但在這種情況下,根本不需要將其作為背景 - 它不會與其他事物同時運(yùn)行.因此,您可以完全忘記 InputCatcher 類,只需像這樣編寫代碼:
to below the two loops. But in this case, there's no need for that to be backgrounded at all - it doesn't run simultaneously with other things. So, you can forget about the InputCatcher class entirely, and just write your code like this:
for usb in usbs:
usb.daemon = True
usb.start()
while True:
input_queue.put(input())
您可能還想考慮一個特定的輸入——比如空字符串——來結(jié)束程序.在主運(yùn)行中輸入,只需結(jié)束循環(huán)就可以輕松完成:
You might also want to consider a particular input - say, the empty string - to end the program. Having the input in the main run makes this really easy by just ending the loop:
while True:
data = input('Type data; or enter to exit: ')
if not data:
break
input_queue.put(data)
這篇關(guān)于input() 正在阻止進(jìn)程的使用的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!