Python:多线程列表附加无法按预期工作

Python:多线程列表附加无法按预期工作,python,multithreading,Python,Multithreading,为什么会出现以下代码(您可以运行它): 印刷品: 1 1 2 1 3 2 4 2 如果我注释掉sleep(1)部分,它会打印出我期望的内容: 1 1 2 2 3 3 4 4 如何修复代码以使其正确附加,最后我在我的列表中有4个元素使用多进程处理,您需要使用共享变量才能从多个进程访问它。在您的代码中,如果没有睡眠,每个进程完成的速度足够快,因此您只需要在池中使用一个进程,因此您的代码将附加到相同的我的列表。当您使用睡眠时,它会使用多个进程,因此您最终会附加到MY_LIST的不同实例 您需要使用

为什么会出现以下代码(您可以运行它):

印刷品:

1 1
2 1
3 2
4 2
如果我注释掉
sleep(1)
部分,它会打印出我期望的内容:

1 1
2 2
3 3
4 4

如何修复代码以使其正确附加,最后我在
我的列表中有4个元素

使用
多进程处理
,您需要使用共享变量才能从多个进程访问它。在您的代码中,如果没有
睡眠
,每个进程完成的速度足够快,因此您只需要在池中使用一个进程,因此您的代码将附加到相同的
我的列表
。当您使用睡眠时,它会使用多个进程,因此您最终会附加到
MY_LIST
的不同实例

您需要使用共享变量才能从每个进程访问它。共享变量需要预先分配大小:

from multiprocessing import pool, Array, current_process

MY_LIST = Array('i', 8)

def worker(j):
    MY_LIST[j-1] = j*j
    print(current_process().name, j, len(MY_LIST))

if __name__ == '__main__':
    parameters= [1, 2, 3, 4, 5, 6, 7, 8]
    with pool.Pool(processes=4) as pool:
        results = pool.map(worker, parameters)
    for i in MY_LIST:
        print(i)
输出:

ForkPoolWorker-1 1 8
ForkPoolWorker-2 2 8
ForkPoolWorker-1 4 8
ForkPoolWorker-3 3 8
ForkPoolWorker-1 5 8
ForkPoolWorker-2 6 8
ForkPoolWorker-1 7 8
ForkPoolWorker-3 8 8
1
4
9
16
25
36
49
64

通过调用
time.sleep
可以发现一种竞争,因为没有它,一个工人在其他工人开始之前就完成了任务。如果您使用较长的列表,这一点会很清楚,例如:

来自multiprocessing.pool导入池的

从时间上导入睡眠
我的清单=[]
def工人(j):
全球我的清单
睡眠(1)
我的清单。附加(j)
打印(j,len(我的清单))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
参数=范围(25)
将池(进程=2)作为池:
结果=pool.map(工作者、参数)
将输出如下内容

11
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
1 13
1 14
1 15
1 16
1 17
1 18
1 19
1 20
1 21
1 1
1 2
1 3
1 4
当然,这不是唯一的问题。另一个问题是,至少不是原始python类型。您需要使用一个或类似的,类似这样的:

来自多处理导入池、锁、管理器的

从时间上导入睡眠
经理=经理()
MY_LIST=manager.LIST()
def工人(j):
全局MY_列表,锁定
我的清单。附加(j)
打印(j,len(我的清单))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
参数=范围(25)
将池(2)作为池:
结果=pool.map(工作者、参数)
哪个会输出

41
5 2
6 3
7 4
8 5
9 6
10 7
11 8
12 10
13 11
0 10
1 13
14 12
2 15
15 15
3 16
16 18
17 19
18 20
20 20
19 22
24 23
21 23
22 24
23 25

当然,这并不能保证秩序,只能保证访问。

奇怪的是,这段代码不会为我执行。我获得属性错误:无法在
@SamMorgan上获得属性“worker”:试试这个:你的目标是什么?当涉及到多个工作线程并行时,您可能需要使用一些同步机制。看起来像是一个时间问题
pool.map
将iterable拆分为块,并将其作为单个任务提交给工作人员。我的猜测是,在没有
sleep
的版本中,其中一个工作人员可以快速抓取所有四个任务并执行它们,而带有
sleep
的版本允许两个工作人员分别抓取两个任务。您可以在
worker
函数中
打印(多处理。当前进程().name,j,len(我的列表))
,查看是否存在这种情况。
ForkPoolWorker-1 1 8
ForkPoolWorker-2 2 8
ForkPoolWorker-1 4 8
ForkPoolWorker-3 3 8
ForkPoolWorker-1 5 8
ForkPoolWorker-2 6 8
ForkPoolWorker-1 7 8
ForkPoolWorker-3 8 8
1
4
9
16
25
36
49
64