【发布时间】:2014-11-23 13:49:46
【问题描述】:
我正在用 python (ver 2.7) 开发一个小的 irc 客户端。我曾希望使用多处理来读取我当前连接的所有服务器,但我遇到了问题
import socket
import multiprocessing as mp
import types
import copy_reg
import pickle
def _pickle_method(method):
func_name = method.im_func.__name__
obj = method.im_self
cls = method.im_class
return _unpickle_method, (func_name, obj, cls)
def _unpickle_method(func_name, obj, cls):
for cls in cls.mro():
try:
func = cls.__dict__[func_name]
except KeyError:
pass
else:
break
return func.__get__(obj, cls)
copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)
class a(object):
def __init__(self):
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock1.connect((socket.gethostbyname("example.com"), 6667))
self.servers = {}
self.servers["example.com"] = sock1
def method(self, hostname):
self.servers[hostname].send("JOIN DAN\r\n")
print "1"
def oth_method(self):
pool = mp.Pool()
## pickle.dumps(self.method)
pool.map(self.method, self.servers.keys())
pool.close()
pool.join()
if __name__ == "__main__":
b = a()
b.oth_method()
每当它到达pool.map(self.method, self.servers.keys()) 行时,我就会收到错误消息
TypeError: expected string or Unicode object, NoneType found
根据我的阅读,当我尝试腌制不可腌制的东西时会发生这种情况。为了解决这个问题,我首先按照here 的描述制作了_pickle_method 和_unpickle_method。然后我意识到我(最初)试图传递pool.map() 一个套接字列表(非常不可挑选),所以我将其更改为主机名列表,因为字符串可以被腌制。但是,我仍然收到此错误。
然后我尝试直接在self.method、self.servers.keys() 和self.servers.keys()[0] 上调用pickle.dumps()。正如预期的那样,后两者效果很好,但从第一个我得到
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled.
更多研究将我引向this question,这似乎表明问题出在套接字的使用上(而gnibbler's answer 对该问题似乎证实了这一点)。
有没有一种方法可以让我实际使用多处理?从我(非常简短地)阅读的内容来看,pathos.multiprocessing 可能是我需要的,但如果可能的话,我真的很想坚持使用标准库。
我也不打算使用多处理 - 如果多线程可以更好地工作并避免这个问题,那么我对这些解决方案持开放态度。
【问题讨论】:
-
您实际上是在尝试将套接字传递给子进程,还是只是您试图避免的意外发生的事情?对于前者,您需要迁移套接字,这必须在比 Python 酸洗更低的级别完成,并且每个平台都不同,因为在幕后,套接字只是文件描述符的包装器,并且您需要操作系统使相同的文件描述符意味着您的子进程中的相同套接字。
-
同时,您使用多处理而不是多线程是有原因的吗? “从一堆服务器中读取数据”几乎与 I/O 绑定的范例案例一样接近,这正是线程的优点。
-
首先,“Python 中的线程很慢”是不正确的。 如果你有 CPU 绑定代码,Python 中的线程会很慢,因为只有一个线程可以同时执行指令。如果您的线程几乎将所有时间都花在等待套接字接收或类似上,那么线程就没有问题,并且进程只会增加开销和复杂性而没有任何好处。
-
第二,“我正在将子进程的字符串键传递给引用套接字的字典”。那么……它是如何得到那本词典的?这个特定于 Unix 的代码是否依赖于在启动时继承父级状态的子级?如果是这样,那么您为什么认为问题与酸洗套接字有关?如果不是,那您为什么认为没有必要进行套接字迁移?
-
同时,您链接的问题的答案说使用协议 -1 而不是默认值将解决问题。你试过吗?如果有,发生了什么?
标签: python sockets multiprocessing pickle irc