在Windows上使用Python 2.7,并将使用支持真正多线程的Jython。方法sendMessage
用于接收来自特定客户端的消息,客户端可以将相同的消息发送给其他几个客户端(参数receivers
的用途是什么,receivers
是一个列表)。方法receiveMessage
用于接收从其他客户端发送的特定客户端的消息。
问题是我是否需要方法sendMessage
和receiveMessage
的任何锁定?我认为没有必要,因为即使客户端X正在接收其消息,对于另一个客户端Y附加到消息池以向客户端X传递消息也是完美的。我认为对于defaultdict / list,append / pop是无论是原子还是无需保护。
如果我错了,请随时纠正我。
from collections import defaultdict
class Foo:
def __init__(self):
# key: receiver client ID, value: message
self.messagePool = defaultdict(list)
def sendMessage(self, receivers, message):
# check valid for receivers
for r in receivers:
self.messagePool[r].append(message)
def receiveMessage(self, clientID):
result = []
while len(self.messagePool[clientID]) > 0:
result.append(self.messagePool[clientID].pop(0))
return result
答案 0 :(得分:4)
我建议使用Queue
代替list
。它被设计用于在带有锁定的线程中附加\ pop。
答案 1 :(得分:3)
我认为这个问题已经为CPython here和here得到了很好的回答(基本上,你因为GIL而安全,但文档中没有任何内容(例如defaultdict)或list)正式谈到这一点)。但我理解你对Jython的关注,所以让我们使用一些官方来源解决它,比如Jython source code。 pythonic list
是javaish PyList
,有这种代码:
public void append(PyObject o) {
list_append(o);
}
final synchronized void list_append(PyObject o) {
...
}
public PyObject pop(int n) {
return list_pop(n);
}
final synchronized PyObject list_pop(int n) {
...
}
由于我们有这些方法synchronized,我们可以确定列表追加和弹出对Jython也是线程安全的。因此,您的代码似乎是安全的线程。
虽然Queue
建议仍然有效,但这个用例确实更合适。
答案 2 :(得分:2)
竞争条件是两个或多个线程同时改变某些全局状态。
在sendMessage
的代码中,您正在更改self.messagePool[r]
,这是一个全局对象。因此,在添加新项目之前应锁定self.messagePool[r]
。
与您的receiveMessage
功能相同。
list.append
和list.pop
是操作O(1)和O(1)操作,所以它很少会导致任何竞争条件。但是,风险仍然存在。