当前位置: 首页 > 知识库问答 >
问题:

用于多处理的共享内存中的大型numpy阵列:这种方法有问题吗?

呼延才
2023-03-14

多处理是一个很好的工具,但是使用大内存块并不简单。您可以在每个进程中加载块并将结果转储到磁盘上,但有时您需要将结果存储在内存中。最重要的是,使用奇特的数字功能。

我读了很多书/在谷歌上搜索了很多,并找到了一些答案:

在共享内存中使用Numpy数组进行多重处理

在多处理进程之间共享大型只读Numpy数组

Python多重处理全局Numpy数组

如何在python子进程之间传递大型numpy数组而不保存到磁盘?

等等等等等等。

它们都有缺点:不是很主流的库(sharedmem);全局存储变量;代码、管道等不太容易阅读。

我的目标是在我的员工中无缝地使用numpy,而不必担心转换和其他问题。

经过多次试验,我想出了这个。它在我的ubuntu 16、python 3.6、16GB、8核机器上运行。与以前的方法相比,我做了很多“捷径”。没有全局共享状态,没有需要在worker内部转换为numpy的纯内存指针,没有作为进程参数传递的大型numpy数组,等等。

上面是Pastebin链接,但我将在这里放几个片段。

一些进口:

import numpy as np
import multiprocessing as mp
import multiprocessing.sharedctypes
import ctypes

分配一些共享的mem,并将其包装成Numpy数组:

def create_np_shared_array(shape, dtype, ctype)
     . . . . 
    shared_mem_chunck = mp.sharedctypes.RawArray(ctype, size)
    numpy_array_view = np.frombuffer(shared_mem_chunck, dtype).reshape(shape)
    return numpy_array_view

创建共享数组并在其中放入一些内容

src = np.random.rand(*SHAPE).astype(np.float32)
src_shared = create_np_shared_array(SHAPE,np.float32,ctypes.c_float)
dst_shared = create_np_shared_array(SHAPE,np.float32,ctypes.c_float)
src_shared[:] = src[:]  # Some numpy ops accept an 'out' array where to store the results

生成流程:

p = mp.Process(target=lengthly_operation,args=(src_shared, dst_shared, k, k + STEP))
p.start()
p.join()

以下是一些结果(请参见pastebin代码以获取完整参考):

Serial version: allocate mem 2.3741257190704346 exec: 17.092209577560425 total: 19.46633529663086 Succes: True
Parallel with trivial np: allocate mem 2.4535582065582275 spawn  process: 0.00015354156494140625 exec: 3.4581971168518066 total: 5.911908864974976 Succes: False
Parallel with shared mem np: allocate mem 4.535916328430176 (pure alloc:4.014216661453247 copy: 0.5216996669769287) spawn process: 0.00015664100646972656 exec: 3.6783478260040283 total: 8.214420795440674 Succes: True

我还做了一个cProfile(为什么在分配共享mem时多2秒钟?)并意识到有一些对_io的tempfile.py{方法'写'的调用。BufferedWriter'对象}

问题

  • 我做错什么了吗
  • (大型)阵列是否来回酸洗,而我没有获得任何速度?请注意,第二次运行(使用常规np数组无法通过正确性测试)
  • 是否有办法进一步改进时间安排、代码清晰度等?(wrt到多处理范式)

笔记

  • 我无法处理进程池,因为mem必须在fork处继承,而不是作为参数发送

共有1个答案

佟阳飙
2023-03-14

共享阵列的分配很慢,因为它显然是先写入磁盘的,所以可以通过mmap共享。有关参考信息,请参阅heap。py和sharedTypes。皮耶。这就是为什么tempfile。py显示在探查器中。我认为这种方法的优点是在崩溃时会清理共享内存,而POSIX共享内存无法保证这一点。

多亏了fork,您的代码不会发生酸洗,正如您所说,内存是继承的。第二次运行不起作用的原因是因为子进程不允许在父进程的内存中写入。相反,私有页面是动态分配的,只有在子进程结束时才会被忽略。

我只有一个建议:您不必自己指定ctype,可以通过np从numpy数据类型中找出正确的类型。ctypeslib_类型代码。或者只需对所有内容使用c_byte,并使用dtype itemsize计算缓冲区的大小,它将由numpy进行强制转换。

 类似资料:
  • 问题内容: 我有三个大名单。前一个包含位数组(模块位数组0.8.0),另外两个包含整数数组。 这些数据结构占用相当多的RAM(总计约16GB)。 如果我使用以下方法启动12个子流程: 这是否意味着将为每个子流程复制l1,l2和l3,或者子流程将共享这些列表?或者更直接地说,我将使用16GB还是192GB的RAM? someFunction将从这些列表中读取一些值,然后根据读取的值执行一些计算。结果

  • 问题内容: 我想在共享内存中使用一个numpy数组,以便与多处理模块一起使用。困难是像numpy数组一样使用它,而不仅仅是ctypes数组。 这将产生如下输出: 可以ctypes方式访问该数组,例如arr[i]说得通。但是,它不是一个numpy数组,因此我无法执行,或。我想一个解决方案是将数组转换为数组。但是(除了无法完成这项工作外),我不相信会再共享它。 对于必须解决的常见问题,似乎将有一个标准

  • 问题内容: 多重处理是python中的强大工具,我想更深入地了解它。我想知道何时使用 常规的 锁和队列,何时使用多处理管理器在所有进程之间共享它们。 我提出了以下测试方案,其中包含四种不同的条件进行多处理: 使用池和 NO Manager 使用池和管理器 使用单个流程和 NO Manager 使用单个流程和一个经理 工作 所有条件都执行作业功能。包括一些通过锁固定的打印件。此外,该函数的输入只是放

  • 问题内容: 有时,您必须对一个或多个大型Numpy阵列执行许多中间操作。这会很快导致s。在我到目前为止的研究中,U发现酸洗(Pickle,CPickle,Pytables等)是缓解此问题的方法。我想知道经验丰富的程序员在处理大量数据时是否还会使用其他任何技术(当然,除了消除策略/代码中的冗余之外)。 另外,如果我确定有一件事,那就是没有免费的东西。使用其中一些技术,需要进行哪些权衡(例如,速度,鲁

  • 我正在使用POSIX共享内存和未命名信号量实现客户机服务器。服务器可以同时处理多个客户端。该代码适用于单个客户端,但不适用于多个客户端。POSIX操作是用,

  • 问题内容: 第一个问题是Value和Manager()。Value有什么区别? 其次,是否可以不使用Value共享整数变量?下面是我的示例代码。我想要的是获取一个整数值而不是Value的字典。我所做的就是在此过程之后全部更改。有没有更简单的方法? 问题答案: 使用时,您会在共享内存中获得一个对象,默认情况下,该对象使用进行同步。使用该对象时,您将得到一个控制服务器进程的对象,该服务器进程允许对象值

  • 我尝试编写一个共享内存和信号量程序,该程序一直运行到按下Ctrl+C,即接收到: 当按下Ctrl+C时,被设置为,它会跳出循环并退出。在没有共享内存和信号量的情况下,这可以很好地工作,但是在这里,我从来没有在上获得字符串,只捕获并且它继续运行。 为什么?

  • 本文向大家介绍python中常用的九种预处理方法分享,包括了python中常用的九种预处理方法分享的使用技巧和注意事项,需要的朋友参考一下 本文总结的是我们大家在python中常见的数据预处理方法,以下通过sklearn的preprocessing模块来介绍; 1. 标准化(Standardization or Mean Removal and Variance Scaling) 变换后各维特征有