Python:socket.rcvfrom()锁定所有脚本

时间:2018-07-05 20:09:00

标签: python python-3.x

我在python 3中有一个使用时间表和套接字的简单代码:

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独立运行此工作?更好的主意是在线程中运行它?

1 个答案:

答案 0 :(得分:1)

可以在此处使用线程,它可以正常工作,但是需要进行一些更改。首先,后台线程上的调度程序将尝试每秒钟启动一个新的recvfrom,无论最后一个花费了多长时间。其次,由于两个线程显然都试图调用相同的writeToBuffer函数,因此您可能需要Lock或其他东西才能使它们同步。

几乎可以肯定,围绕异步事件循环重写整个程序在这里是很过分的。

仅将套接字更改为非阻塞并进行混合可能是最简单的更改,例如,使用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秒是个好主意,所以在下一个时间表开始之前,还有时间做所有其他工作。)

在幕后,通过将OS级套接字设置为非阻塞模式并执行一些特定于实现的事情来等待超时,可以起作用。您可以使用setblocking(False)并使用selectselectors模块来自己做同样的事情,以等待最多0.8秒的时间来准备好套接字,但是让Python保重会更容易为您服务。