python - 这个python代码线程安全吗(扭曲的线程)?

标签 python multithreading udp twisted

我正在编写一个应用程序来收集 UDP 消息并每 1 秒处理一次。

应用程序原型(prototype)如下:

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import threading
import time

class UdpListener(DatagramProtocol):

    messages = []

    def datagramReceived(self, data, (host, port)):
        self.messages.append(data)

class Messenger(threading.Thread):

    listener = None

    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            time.sleep(1)
            recivedMessages = self.listener.messages
            length = len(recivedMessages)
            messagesToProccess = recivedMessages[0:length]
            #doSomethingWithMessages(messagesToProccess)
            del self.listener.messages[0:length]
            print(length)

listener = UdpListener()

messenger = Messenger()
messenger.listener = listener
messenger.start()

reactor.listenUDP(5556, listener)
reactor.run()

我不确定我是否可以轻松地从列表 (del self.listener.messages[0:length]) 中删除起始值,而不会有任何传入消息更改列表和应用程序崩溃的风险。

更新 - 带锁的版本

class Messenger(threading.Thread):

listener = None
lock = threading.Lock()

def __init__(self):
    threading.Thread.__init__(self)

def run(self):
    while True:
        time.sleep(1)
        recivedMessages = self.listener.messages
        self.lock.acquire()
        try:
            length = len(recivedMessages)
            messagesToProccess = recivedMessages[0:length]
            del self.listener.messages[0:length]
        except Exception as e:
            raise e
        finally:
            self.lock.release()

        #doSomethingWithMessages(messagesToProccess)
        print(length)

最佳答案

您的代码不是线程安全的,不是。您需要锁定消息

但是,您在这里不需要线程。为什么不这样做呢?

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class UdpListener(DatagramProtocol):
    callingLater = False

    messages = []

    def process(self):
        doSomethingWithMessages(self.messages)
        self.messages = []
        self.callingLater = False

    def datagramReceived(self, data, (host, port)):
        self.messages.append(data)
        if not self.callingLater:
            reactor.callLater(1.0, self.process)
            self.callingLater = True

listener = UdpListener()

reactor.listenUDP(5556, listener)
reactor.run()

更新:以下是原始版本如何使用锁,仅用于教育目的。请注意,这效率不高,而且更容易出现错误。编辑:将所有消息逻辑分离到 UdpListener 中,因此使用它的类不需要知道其内部细节。

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import threading
import time

class UdpListener(DatagramProtocol):
    message_lock = threading.Lock()
    messages = []

    def datagramReceived(self, data, (host, port)):
        with self.message_lock:
            self.messages.append(data)

    def getAndClearMessages(self):
        with self.message_lock:
            res = self.messages
            self.messages = []
        return res

class Messenger(threading.Thread):

    listener = None

    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            time.sleep(1)
            recivedMessages = self.listener.getAndClearMessages()
            length = len(recivedMessages)
            #doSomethingWithMessages(recivedMessages)
            print(length)

listener = UdpListener()

messenger = Messenger()
messenger.listener = listener
messenger.start()

reactor.listenUDP(5556, listener)
reactor.run()

关于python - 这个python代码线程安全吗(扭曲的线程)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11369845/

相关文章:

python - Python 或 Bash 或 CLI 中的 SQLite 数据更改通知回调

python - 如何使用Python3在pyqt5中正确锁定Qthreads

linux - 为什么线程只以大间隔同步?

linux - sendmsg 失败,错误代码 3 (ESRCH)

python - MySQLdb fetcall,AttributeError : 'int' object has no attribute 'fetchall'

python - 在 Pandas DF 中迭代多列并动态切片

c# - 单个 "lock"或单独的读写器锁用于 IO 操作?

c - 将 UDP 数据包发送到死服务器

Android通过本地wifi进行UDP通信

python - 使用点击事件计算两个坐标之间的距离