numpy 使用多处理和time.strftime()创建绘图无法正常工作

sxissh06  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(93)

我试图创建与我的脚本并行运行使用多处理的情节。我在这里为我的问题创建了两个示例脚本,因为包含计算部分的实际主脚本太长了。在www.example.com中script0.py你可以看到多处理部分,在那里我启动了实际的script1.py,并行地做了4次。在这个例子中,它只是创建一些随机散点图。
script0.py:

import multiprocessing as mp
import os

def execute(process):
    os.system(f"python {process}")


if __name__ == "__main__":

    proc_num = 4
    process= []

    for _ in range(proc_num):
        process.append("script1.py")

    process_pool = mp.Pool(processes= proc_num)
    process_pool.map(execute, process)

script1.py:

#just a random scatterplot, but works for my example
    import time
    import numpy as np
    import matplotlib.pyplot as plt
    import os
    
    dir_name = "stackoverflow_question"
    plot_name = time.strftime("Plot %Hh%Mm%Ss")      #note the time.strftime() function
    
    if not os.path.exists(f"{dir_name}"):
        os.mkdir(f"{dir_name}")
    
    N = 50
    x = np.random.rand(N)
    y = np.random.rand(N)
    colors = np.random.rand(N)
    
    area = (30 * np.random.rand(N))**2
    
    plt.scatter(x,y, s=area, c=colors, alpha=0.5)
    #plt.show()
    plt.savefig(f"{dir_name}/{plot_name}", dpi = 300)

重要的是,我以创作时间来命名这个情节
plot_name = time.strftime(“Plot %Hh%Mm%Ss”)
这就创建了一个类似“Plot 16 h39 m22 s”的字符串。到目前为止一切顺利。。现在来谈谈我的实际问题!我意识到,当并行启动进程时,有时绘图名称是相同的,因为time.strftime()创建的时间戳是相同的,因此可能会发生www.example.com的一个示例script1.py覆盖另一个示例已经创建的绘图。
在我的工作脚本中,我有这个确切的问题,我生成了很多数据,因此我需要根据它们生成的日期和时间来命名我的图和CSV。
我已经想过在www.example.com被调用时给它一个变量script1.py,但我不知道如何实现,因为我刚刚了解了多处理库。但这个变量也必须变化,否则我会遇到同样的问题。
有没有人有一个更好的主意,我如何才能实现这一点?先谢谢你了。

yftpprvb

yftpprvb1#

我提出这些方法:

  • 方法1:(简单且推荐)如果你可以更改名称,我推荐使用unixtime(例如:使用time.time()或time.time_ns())而不是date或将小数添加到秒。这样一来,碰撞几乎是不可能的。
  • 方法2:在文件名中添加process id(例如:)<filename_timestamp_processid>。这样即使两个进程同时写,你也可以用进程id来区分文件。如果你想在执行结束时从文件名中删除id,请读取文件名并进行合并,如果有冲突,请以适当的方式调整文件名。
  • 方法3:与方法2类似,但不是更改名称,而是创建一个以进程id命名的文件夹,将该进程的输出放在其中。在执行结束时,合并文件夹并纠正任何冲突。
  • 方法4:(不推荐,难以管理,影响性能)shared memory。你在共享内存中使用一个变量和最后一个时间戳,并检查它。
xjreopfe

xjreopfe2#

一些想法...
首先,您没有遵循multiprocessing模块中关于如何使用Pool的指导原则。您应该将其放在上下文管理器with(...)...
有很多例子。请参见DOX中的红色警告:
https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing.pool
另外,使用os.system调用有点奇怪/不安全。为什么不把绘图例程放到同一个模块或不同模块的标准函数中,然后导入它呢?这将允许你传递额外的信息(比如一个好的标签)给函数。我希望像这样的东西,其中source是一个内存或外部源...

def make_plot(source, output_file_name, plot_label):
    # read the data source
    # make the plot
    # save it to the output path...

就标签而言,如果你在同一个“秒”内启动这些进程,当然会有重叠,所以你可以在标签上附加进程号,或者其他一些信息,比如来自数据源的信息,或者使用相同的时间戳,但是把输出放在唯一的文件夹中,就像另一个答案中建议的那样。
我觉得这样的事...

编码:

from multiprocessing import Pool
import time

def f(data, output_folder, label):
    # here data is just an integer, in yours, it would be the source of the graph data...
    val = data * data
    # the below is just example...  you could just use your folder making/saving routine...
    return f'now we can save {label} in folder {output_folder} with value: {val}'

if __name__ == '__main__':
    with Pool(5) as p:
        folders = ['data1', 'data2', 'data3']
        labels = [time.strftime("Plot %Hh%Mm%Ss")]*3
        x_s = [1, 2, 3]
        output = p.starmap(f, zip(x_s, folders, labels))
        for result in output:
            print(result)

输出:

now we can save Plot 08h55m17s in folder data1 with value: 1
now we can save Plot 08h55m17s in folder data2 with value: 4
now we can save Plot 08h55m17s in folder data3 with value: 9

相关问题