我可能在这里有点过头,但我正在研究python中的一个小生物信息学项目。我试图并行一个程序,分析一组字符串的大型字典(RAM中约2-3GB)。我发现当我使用较小的字典时,多处理版本会更快,但是对于大字典而言,它几乎没有什么好处。我的第一个理论是,内存耗尽只会减慢一切,瓶颈就是交换到虚拟内存。但是,我在具有4 * 48GB RAM的群集上运行程序,并且发生了相同的减速。我的第二个理论是对某些数据的访问被锁定。如果一个线程试图访问当前正在另一个线程中访问的引用,该线程是否必须等待?我曾尝试创建我想要操作的词典的副本,但这似乎非常低效。还有什么可能导致我的问题?
我的多处理方法如下:
def worker(seqDict, oQueue):
#do stuff with the given partial dictionary
oQueue.put(seqDict)
oQueue = multiprocessing.Queue()
chunksize = int(math.ceil(len(sdict)/4)) # 4 cores
inDict = {}
i=0
dicts = list()
for key in sdict.keys():
i+=1
if len(sdict[key]) > 0:
inDict[key] = sdict[key]
if i%chunksize==0 or i==len(sdict.keys()):
print(str(len(inDict.keys())) + ", size")
dicts.append(copy(inDict))
inDict.clear()
for pdict in dicts:
p =multiprocessing.Process(target = worker,args = (pdict, oQueue))
p.start()
finalDict = {}
for i in range(4):
finalDict.update(oQueue.get())
return finalDict
答案 0 :(得分:2)
正如我在评论中所说,并且正如Kinch在他的回答中所说的那样,所有传递给子进程的东西都必须进行pickle和unpickled以在生成的进程的本地上下文中复制它。如果对multiprocess.Manager.dict
使用sDict
(从而允许进程通过代理在其上创建的对象的服务器共享相同的数据),并将具有切片索引的进程生成到该共享sDict
,这应该减少产生子进程所涉及的序列化/反序列化序列。尽管在使用共享对象的服务器通信步骤中,您仍然可能遇到瓶颈。如果是这样,您必须考虑简化数据,以便可以使用multiprocess.Array
或multiprocess.Value
使用真正的共享内存,或者查看multiprocess.sharedctypes
来创建自定义数据结构以在您的进程之间共享。
答案 1 :(得分:1)
似乎来自“大型字符串集”的数据可以重新格式化为可以存储在文件或字符串中的内容,允许您使用mmap
模块在所有文件或字符串中共享它流程。如果需要将数据转换回其他更优选的形式,每个进程可能会产生一些启动开销,但是可以通过将每个进程传递给共享内存中指示整个数据集的哪个子集来进行工作来实现最小化。重建该过程所需的部分。
答案 2 :(得分:0)
通过队列传递的每个数据都将使用pickle进行序列化和反序列化。如果你传递大量数据,我猜这可能是一个瓶颈。
你可以减少数据量,利用共享内存,在ac扩展中编写多线程版本,或者使用python的多线程安全实现来尝试多线程版本(也许是jython或pypy;我不知道知道)。
哦顺便说一下:你正在使用多处理而不是多线程。