python - Python:socket.rcvfrom() 锁定所有脚本
问题描述
我在 python 3 中有一个使用 schedule 和 socket 的简单代码:
import schedule
import socket
from time import sleep
def readDataFromFile():
data = []
with open("/tmp/tmp.txt", "r") as f:
for singleLine in f.readlines():
data.append(str(singleLine))
if(len(data)>0):
writeToBuffer(data)
def readDataFromUDP():
udpData = []
rcvData, addr = sock.recvfrom(256)
udpData.append(rcvData.decode('ascii'))
if(len(udpData)>0):
writeToBuffer(udpData)
.
.
.
def main():
schedule.every().second.do(readDataFromFile)
schedule.every().second.do(readDataFromUDP)
while(1):
schedule.run_pending()
sleep(1)
UDP_IP = "192.xxx.xxx.xxx"
UDP_PORT = xxxx
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
main()
问题是,脚本挂在 sock.rcvfrom() 指令上,等待数据到来。如何强制 python 独立运行这项工作?更好的主意是在线程中运行它?
解决方案
您可以在此处使用线程,它会正常工作,但需要进行一些更改。首先,后台线程上的调度程序将尝试recvfrom
每秒启动一个新线程,无论最后一个线程花费了多长时间。其次,由于两个线程显然都在尝试调用相同的writeToBuffer
函数,因此您可能需要 aLock
或其他东西来同步它们。
围绕异步事件循环重写整个程序在这里几乎肯定是矫枉过正。
只需将套接字更改为非阻塞并进行混合可能是最简单的更改,例如,通过使用settimeout
:
# wherever you create your socket
sock.settimeout(0.8)
# ...
def readDataFromUDP():
udpData = []
try:
rcvData, addr = sock.recvfrom(256)
except socket.timeout:
return
udpData.append(rcvData.decode('ascii'))
if(len(udpData)>0):
writeToBuffer(udpData)
现在,每次调用时recvfrom
,如果有可用数据,您将立即处理;如果没有,它将等待最多 0.8 秒,然后引发异常,这意味着您没有要处理的数据,所以返回并等待下一个循环。(这个 0.8 并没有什么神奇之处;我只是认为少于 1 秒的时间会是个好主意,所以在下一个计划时间到来之前还有时间做所有其他工作。)
Under the covers, this works by setting the OS-level socket to non-blocking mode and doing some implementation-specific thing to wait with a timeout. You could do the same yourself by using setblocking(False)
and using the select
or selectors
module to wait up to 0.8 seconds for the socket to be ready, but it's easier to just let Python take care of that for you.
推荐阅读
- ruby - 当 chef-client 运行不成功时,如何编写 chef_handler 来发送邮件?
- kubernetes - Kubernetes服务之间的通信
- ionic-framework - 离子服务稍后再试[无法加载 index.html]
- python - 具有(显然)3 个输入层和一个矩阵输出的 Python 神经网络
- parsing - browser/ballot.sol:102:18: ParserError: Expected '{' but got identifier contract token is ERC20Interface, Owned, SafeMath { ^----^
- android - 如何将每个布局与相同大小的图像相关联
- mongoose - 猫鼬:名称为“”的鉴别器已经存在
- r - 使用 flextable 包错误从 rmarkdown 生成 word 中的表
- typescript - Firebase 上传多个 Storage/Firestore
- angular - 合并两个 observables 然后转换结果