我想使用multiprocessing.Value
+ multiprocessing.Lock
在不同的进程之间共享一个计数器。例如:
import itertools as it
import multiprocessing
def func(x, val, lock):
for i in range(x):
i ** 2
with lock:
val.value += 1
print('counter incremented to:', val.value)
if __name__ == '__main__':
v = multiprocessing.Value('i', 0)
lock = multiprocessing.Lock()
with multiprocessing.Pool() as pool:
pool.starmap(func, ((i, v, lock) for i in range(25)))
print(counter.value())
这将引发以下异常:
RuntimeError:同步的对象仅应在以下对象之间共享 通过继承进行处理
我最困惑的是,一个相关的(虽然不是完全相似的)模式适用于multiprocessing.Process()
:
if __name__ == '__main__':
v = multiprocessing.Value('i', 0)
lock = multiprocessing.Lock()
procs = [multiprocessing.Process(target=func, args=(i, v, lock))
for i in range(25)]
for p in procs: p.start()
for p in procs: p.join()
现在,我认识到这是两个明显不同的东西:
cpu_count()
的工作进程,并在它们之间拆分了一个可迭代的range(25)
那就是说:如何以这种方式与pool.starmap()
(或pool.map()
)共享一个实例?
我见过类似的问题here,here和here,但是这些方法似乎不适合.map()
/ .starmap()
,关于Value
是否使用ctypes.c_int
的看法。
我意识到这种方法在技术上是可行的:
def func(x):
for i in range(x):
i ** 2
with lock:
v.value += 1
print('counter incremented to:', v.value)
v = None
lock = None
def set_global_counter_and_lock():
"""Egh ... """
global v, lock
if not any((v, lock)):
v = multiprocessing.Value('i', 0)
lock = multiprocessing.Lock()
if __name__ == '__main__':
# Each worker process will call `initializer()` when it starts.
with multiprocessing.Pool(initializer=set_global_counter_and_lock) as pool:
pool.map(func, range(25))
这真的是最佳做法吗?
答案 0 :(得分:1)
使用Cadre
时获得的run
是因为在通过(内部池)队列发送到工作进程之前,对池方法的参数进行了腌制。
您要使用哪种池方法与此处无关。当您仅使用import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Cadre());
}
public static class Cadre extends JFrame implements Runnable {
// private PanneauHaut panneauHaut;
// private PanneauBas panneauBas;
@Override
public void run() {
System.out.println("Thread started");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// setExtendedState(JFrame.MAXIMIZED_BOTH);
// this.panneauHaut = new PanneauHaut();
// this.panneauBas = new PanneauBas();
JPanel mainPanel = new JPanel();
JTextField kooltxt = new JTextField("hehehe");
mainPanel.setLayout(new BorderLayout());
mainPanel.add(kooltxt);
// mainPanel.add(panneauHaut, BorderLayout.NORTH);
// mainPanel.add(panneauBas.getPanel(), BorderLayout.SOUTH);
this.setContentPane(mainPanel);
pack();
setLocationRelativeTo(null);
this.setVisible(true);
}
}
}
时不会发生这种情况,因为不涉及队列。您可以仅使用RuntimeError
重现该错误。
您的最后一个代码段不符合您的想法。您不是共享一个Pool
,而是为每个子进程重新创建独立的计数器。
如果您在Unix上并使用默认的启动方法“ fork”,则只需不将共享对象作为参数传递给池方法即可。
您的子进程将通过派生继承全局变量。如果使用流程启动方法“ spawn”(默认Windows)或“ forkserver”,则在Process
期间必须使用pickle.dumps(multiprocessing.Value('i', 0))
实例化,以使子进程继承共享对象。
请注意,这里不需要额外的Value
,因为initializer
默认带有一个可以使用的内部变量。
Pool