我有一个无限循环,其中有些操作在退出循环之前必须完全执行。也就是说,我正在使用套接字库连接到外部设备,并且我需要等待读取指令完成才能中断循环。
我尝试使用信号处理程序(如 this question )在检测到键盘中断时引发标志。
当前代码:
import videosensor
import signal
def signal_handler(signal, frame):
"""Raises a flag when a keyboard interrupt is raised."""
global interrupted
interrupted = True
if __name__ == '__main__':
camera = videosensor.VideoSensor(filename)
interrupted = False
signal.signal(signal.SIGINT, signal_handler)
while not interrupted:
location = camera.get_register()
#...
#More irrelevant stuff is executed.
#...
time.sleep(0.01)
#This code has to be executed after exiting while loop
camera_shutdown(camera)
在前面的代码中,videosensor.VideoSensor是一个包含用于从外部设备获取数据的套接字操作的类。主例程中使用的 get_register() 方法如下:
def get_register(self):
"""Read the content of the specified register.
"""
#Do some stuff
value = socket.recv(2048)
return value
问题:
我希望 while 循环持续执行,直到用户按下按键或使用键盘中断,但在当前迭代完成之后。相反,使用以前的解决方案并不能按预期工作,因为它会中断正在进行的指令,并且如果它正在读取套接字,则会引发错误:
<小时/>/home/.../client.pyc in read_register(self, regkey)
164 reg = self._REGISTERS[regkey] 165 self.send('r,{}\n'.format(reg)) --> 166 value = socket.recv(2048) 167 #Convert the string input into a valid value e.g. list or int 168 formatted_result = ast.literal_eval(value)
error: [Errno 4] Interrupted system
编辑:从下面的答案来看,似乎没有办法使用键盘中断并避免套接字读取功能被中止。尽管有捕获错误的解决方案,但它们无法避免读取取消。
不过,我有兴趣找到一种获取用户输入的方法,例如特定的按键按下,会引发标志,该标志将在循环结束时进行检查,而不会中断主例程的执行,直到进行此检查。
编辑2:使用的操作系统是Linux发行版Ubuntu 14.04
最佳答案
经过快速搜索,我发现 this solution for your issue
基本上,您无能为力:当您向进程发送 SIGINT 时,套接字也会返回 SIGINT。那么,您能做的最好的事情就是通过捕获套接字 EINTR
错误并继续循环来主动忽略该问题:
import errno
try:
# do something
value = conn.recv(2048)
except socket.error as (code, msg):
if code != errno.EINTR:
raise
<小时/>
避免 C-c
中断读取问题的替代解决方案是使用并行执行,在例程中读取套接字,并在另一个套接字上处理用户输入:
import asyncio
async def camera_task(has_ended, filename):
camera = videosensor.VideoSensor(filename)
try:
while not has_ended.is_set():
location = camera.get_register()
#...
#More irrelevant stuff is executed.
#...
await asyncio.sleep(0.01)
finally:
#This code has to be executed after exiting while loop
camera_shutdown(camera)
async def input_task(shall_end):
while True:
i = input("Press 'q' to stop the script…")
if i == 'q':
shall_end.set()
def main():
filename = …
#
end_event = asyncio.Event()
asyncio.Task(camera_task(end_event, filename))
asyncio.Task(input_task(end_event))
asyncio.get_event_loop().run_forever()
或使用 threading
import threading, time
def camera_task(has_ended, filename):
camera = videosensor.VideoSensor(filename)
try:
while not has_ended.is_set():
location = camera.get_register()
#...
#More irrelevant stuff is executed.
#...
time.sleep(0.01)
finally:
#This code has to be executed after exiting while loop
camera_shutdown(camera)
def input_task(shall_end):
while True:
i = input("Press 'q' to stop the script…")
if i == 'q':
shall_end.set()
def main():
filename = …
#
end_event = threading.Event()
threads = [
threading.Thread(target=camera_task, args=(end_event, filename)),
threading.Thread(target=input_task, args=(end_event,))
]
# start threads
for thread in threads:
thread.start()
# wait for them to end
for thread in threads:
thread.join()
或使用 multiprocessing :
import multiprocessing, time
def camera_task(has_ended, filename):
camera = videosensor.VideoSensor(filename)
try:
while not has_ended.is_set():
location = camera.get_register()
#...
#More irrelevant stuff is executed.
#...
time.sleep(0.01)
finally:
#This code has to be executed after exiting while loop
camera_shutdown(camera)
def input_task(shall_end):
while True:
i = input("Press 'q' to stop the script…")
if i == 'q':
shall_end.set()
def main():
filename = …
#
end_event = multiprocessing.Event()
processes = [
multiprocessing.Process(target=camera_task, args=(end_event, filename)),
multiprocessing.Process(target=input_task, args=(end_event,))
]
# start processes
for process in processes:
process.start()
# wait for them to end
for process in processes:
process.join()
disclaimer: those codes are untested, and there might be some typos or little errors, but I believe the overall logic should be 👌
关于python - 完成当前迭代后,如何结束带有套接字操作的无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41015323/