使用多进程进行绘图

huangapple go评论65阅读模式
英文:

Plotting with multiprocessing

问题

可以在并行进程中绘制吗?如果不能,请解释原因。

在下面的脚本中,我提供了在循环、ThreadPool和多进程池中绘制的示例。在循环和ThreadPool中,一切都按预期工作。在多进程池中,我们得到了一个空白图。

import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool
from multiprocessing.pool import ThreadPool
from functools import partial

def plot(ax, x, y):
    ax.plot(x, y)

if __name__ == "__main__":
    x = np.linspace(0, 2 * np.pi, 100)
    y_arr = [np.sin(x), np.cos(x)]
    fig, ax = plt.subplots()
    # 如预期工作
    for yi in y_arr:
        plot(ax, x, yi)
    plt.show()
    # 如预期工作
    fig, ax = plt.subplots()
    with ThreadPool(5) as p:
        p.map(partial(plot, ax, x), y_arr)
    plt.show()
    # 不起作用
    fig, ax = plt.subplots()
    with Pool(5) as p:
        p.map(partial(plot, ax, x), y_arr)
    plt.show()

另外,运行以下代码会导致严重崩溃:

with Pool(5) as p:
    p.map(partial(ax.plot, x), y_arr)

引发了来自我的操作系统的崩溃报告。

英文:

Is it possible to plot in parallel processes? If not, can you please explain why this is the case?

In the script below I've provided an example of plotting in a loop, a ThreadPool and a multiprocessing Pool. In the loop and ThreadPool things work as expected. In the multiprocessing Pool we arrive with a blank plot.

import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool
from multiprocessing.pool import ThreadPool
from functools import partial


def plot(ax, x, y):
    ax.plot(x, y)


if __name__ == "__main__":
    x = np.linspace(0, 2 * np.pi, 100)
    y_arr = [np.sin(x), np.cos(x)]
    fig, ax = plt.subplots()
    # works as expected
    for yi in y_arr:
        plot(ax, x, yi)
    plt.show()
    # works as expected
    fig, ax = plt.subplots()
    with ThreadPool(5) as p:
        p.map(partial(plot, ax, x), y_arr)
    plt.show()
    # doesn't work
    fig, ax = plt.subplots()
    with Pool(5) as p:
        p.map(partial(plot, ax, x), y_arr)
    plt.show()

As a side note, running

with Pool(5) as p:
    p.map(partial(ax.plot, x), y_arr)

causes a hard crash multiprocessing/resou
rce_tracker.py:224: UserWarning: resource_tracker: There appear to be 6 leaked semaphore objects to clean up at shutdown
warnings.warn('resource_tracker: There appear to be %d '
prompting a crash report from my os.


</details>


# 答案1
**得分**: 3

问题出在多进程池上。你必须并行绘图,因为每个进程池都创建了一个新的进程,该进程不知道后端的其他绘图。这就是为什么你得到一个空白图的原因。使用 ```matplotlib.use('Agg')```。

<details>
<summary>英文:</summary>

The issue is with the multiprocessing pool. You have to plot in parallel since each pool is creating a new process that isn&#39;t aware of the other plots in the backend. That&#39;s why you are getting a blank plot. Use ```matplotlib.use(&#39;Agg&#39;)```.

import matplotlib
matplotlib.use('Agg')

import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool
from multiprocessing.pool import ThreadPool
from functools import partial

def plot(ax, x, y):
ax.plot(x, y)

if name == "main":
x = np.linspace(0, 2 * np.pi, 100)
y_arr = [np.sin(x), np.cos(x)]
fig, ax = plt.subplots()
for yi in y_arr:
plot(ax, x, yi)
plt.show()
fig, ax = plt.subplots()
with ThreadPool(5) as p:
p.map(partial(plot, ax, x), y_arr)
plt.show()
fig, ax = plt.subplots()
with Pool(5) as p:
p.map(partial(plot, ax, x), y_arr)
plt.show()


</details>



# 答案2
**得分**: 2

不可以轻松地从多个进程绘制到同一窗口,因为每个进程只能绘制到它自己的窗口。多进程生成多个进程,虽然每个进程可以创建自己的窗口进行绘制,但你不能让它们都绘制到同一个窗口,这是操作系统的限制。如果只是保存图形到磁盘,可以使用非 GUI 后端,使用 `matplotlib.use('Agg')`,每个进程可以在内存中绘制图形,然后使用 `plt.savefig` 将其保存到磁盘。图表显示为空是因为每个进程有自己的内存,而 `ax.plot` 仅修改存在于子进程内存中的 `ax` 的副本,如果按照以下方式修改 `plot`,则子进程可以显示它。

```python
import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool
from functools import partial

def plot(ax, x, y):
    ax.plot(x, y)
    plt.show()

if __name__ == "__main__":
    x = np.linspace(0, 2 * np.pi, 100)
    y_arr = [np.sin(x), np.cos(x)]
    fig, ax = plt.subplots()
    with Pool(5) as p:
        p.map(partial(plot, ax, x), y_arr)
    plt.show()

你会得到3个窗口,前两个显示每个子进程的 ax 副本,第三个窗口为空,因为它显示的是父进程的 ax 副本,而这个副本没有被修改。

英文:

> Is it possible to plot in parallel processes? If not, can you please explain why this is the case?

No, you cannot trivially plot to the same window from multiple processes, as each process can only draw to the windows it own, multiprocessing spawns multiple processes, and while each one can create its own window to draw to, you can't have them all drawing to the same window, this is a limitation from the operating system.

If you are just saving the figures to disk you can use a non-gui backend using matplotlib.use(&#39;Agg&#39;), and each process can paint its figure in memory and save it to disk using plt.savefig

the plot appears blank because each process has its own memory, and ax.plot is only modifying the copy of ax that exist in the child process memory, which the child process can show if you modify plot as follows.

import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool
from functools import partial

def plot(ax, x, y):
    ax.plot(x, y)
    plt.show()


if __name__ == &quot;__main__&quot;:
    x = np.linspace(0, 2 * np.pi, 100)
    y_arr = [np.sin(x), np.cos(x)]
    fig, ax = plt.subplots()
    with Pool(5) as p:
        p.map(partial(plot, ax, x), y_arr)
    plt.show()

your get 3 windows, the first 2 are showing each child's copy of ax and the third window is blank as it is showing the parent's copy of ax which is unmodified.

huangapple
  • 本文由 发表于 2023年4月4日 07:20:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75924391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定