Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Numpy 多节点上的mmap_Numpy_Parallel Processing_Mmap - Fatal编程技术网

Numpy 多节点上的mmap

Numpy 多节点上的mmap,numpy,parallel-processing,mmap,Numpy,Parallel Processing,Mmap,下面的脚本使用mmap并行写入内存映射数组。但是,它仅在所有进程都位于同一节点上时才起作用-否则,它会为不在秩0节点上的处理器生成0行,或在输出中生成其他零散值。为什么会这样?我觉得我错过了一些关于mmap如何工作的东西 编辑:在NFS系统和并行分布式系统上都会出现相同的结果。下面的一位评论员建议这与mmap的页面长度有关。当我的切片的“长度”正好为4KB时,脚本仍会生成错误的输出。当切片长度远大于4kib时,也会发生同样的情况 #!/usr/bin/python3 from mpi4py i

下面的脚本使用mmap并行写入内存映射数组。但是,它仅在所有进程都位于同一节点上时才起作用-否则,它会为不在秩0节点上的处理器生成0行,或在输出中生成其他零散值。为什么会这样?我觉得我错过了一些关于mmap如何工作的东西

编辑:在NFS系统和并行分布式系统上都会出现相同的结果。下面的一位评论员建议这与mmap的页面长度有关。当我的切片的“长度”正好为4KB时,脚本仍会生成错误的输出。当切片长度远大于4kib时,也会发生同样的情况

#!/usr/bin/python3

from mpi4py import MPI
import numpy as np

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

length = int(1e6)      # Edited to make test case longer.
myfile = "/tmp/map"

if rank == 0:
    fp = np.memmap(myfile, dtype=np.float32, mode='w+', shape=(size,length))
    del fp

comm.Barrier()

fp = np.memmap(myfile, dtype=np.float32, mode='r+', shape=(1,length),
                offset=rank*length*4)
fp[:,:] = np.full(length,rank)

comm.Barrier()

if rank == 0:
    out = np.memmap(myfile, dtype=np.float32, mode='r', shape=(size,length))
    print(out[:,:])
正确输出:

[[ 0.  0.  0.  0.]
 [ 1.  1.  1.  1.]
 [ 2.  2.  2.  2.]
 [ 3.  3.  3.  3.]
 [ 4.  4.  4.  4.]]
输出不正确。级别为3和4的处理器不进行写入

[[ 0.  0.  0.  0.]
 [ 1.  1.  1.  1.]
 [ 2.  2.  2.  2.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]]

这个答案适用于NFS文件。其他网络文件系统上的YMMV

问题与MPI或
numpy.memmap
无关,而是与Linux内核如何缓存NFS文件数据有关。从一些实验中可以看出,在从NFS服务器请求读取之前,客户机请求最后修改的时间戳。如果此时间戳不比客户机上次写入的时间最近,则将从客户机的缓存中获取数据,而不是再次从服务器请求数据。如果N1和N2是节点,则可能发生以下情况:

  • N1和N2打开相同的零填充文件;文件内容[00],上次修改:t=0.00
  • N1和N2内核请求的文件内容比需要的多,并将其存储在缓存中。N1缓存:[00](t=0.00);N2缓存:[00](t=0.00)
  • 在时间t=0.01时,N2写入文件的后半部分。服务器状态:[02](t=0.01);N1缓存:[00](0.00);N2缓存:[02](0.01)
  • 在时间t=0.02时,N1写入前半部分。服务器:[12](0.02);N1缓存:[10](0.02)。N2缓存:[02](0.01)
  • N1上的进程尝试读取下半部分
  • N1内核从服务器请求最后修改的时间;结果:t=0.02
  • N1内核检索前半部分的过时缓存内容[0]
  • 因此,您需要确保其他客户端(节点)更新时间戳

    if rank == 0:
        fp = np.memmap(myfile, dtype=np.float32, mode='w+', shape=(size,length))
        del fp
    
    comm.Barrier() # B0
    fp = np.memmap(myfile, dtype=np.float32, mode='r+', shape=(1,length),
                    offset=rank*length*4)
    
    comm.Barrier() # B1 (this one may be superfluous)
    fp[:,:] = np.full(length, rank)
    del fp # this will flush the changes to storage
    
    comm.Barrier() # B2
    from pathlib import Path
    from time import sleep
    if rank == 1:
        # make sure that another node updates the timestamp
        # (assuming 1 s granularity on NFS timestamps)
        sleep(1.01)
        Path(myfile).touch()
        sleep(0.1) # not sure
    
    comm.Barrier() # B3
    if rank == 0:
        out = np.memmap(myfile, dtype=np.float32, mode='r', shape=(size,length))
        print(out[:,:])
    
    关于屏障
    B1
    :我没有在这里设置MPI;我用按键模拟它。我不确定这个障碍是否真的有必要。
    睡眠(0.1)
    也可能是不必要的;它只是在
    touch()
    函数返回和NFS服务器接收更新之间出现延迟的情况下出现的

    我假设您对数据进行了安排,以便每个节点访问与4096字节边界对齐的内存映射文件的部分。我使用
    length=4096
    进行测试


    这个解决方案有点像黑客,依赖于NFS驱动程序的未记录行为。这是在Linux内核3.10.0-957上,NFS装载选项包括
    relatime、vers=3、rsize=8192、wsize=8192
    。如果使用这种方法,我建议您包括一个自检:基本上,上面的代码带有一个
    assert
    语句来验证输出。这样,如果它由于不同的文件系统而停止工作,您将捕获它。

    我假设
    /tmp/map
    是一个本地文件,它只存在于运行rank
    0
    的节点上。但是,我很惊讶
    memmap
    在其他节点上没有失败(例如,该文件不存在)。您缺少网络文件系统,例如NFS(速度慢且通用,易于部署,非常流行)或Lustre(快速且并行,难以部署,主要用于HPC)。我在NFS和并行分布式文件系统上都进行了测试,这两种情况下都存在同样的问题。这与内存映射在页面粒度上起作用这一事实有关。页面通常不小于4kib。如果触摸页面中的一个字节,则整个页面将被标记为脏页,然后将其全部刷新到磁盘。无论最后哪个进程通过网络刷新其修改的页面,都将覆盖其他进程所做的更改。当所有进程都位于同一主机上时,这不是问题,因为FS缓存中的同一物理页映射到所有进程中。解决方案是不映射如此小的区域,而是每个进程至少有4 KiB。请注意,即使您的数组是
    1 x 4 x 4=16
    字节,内存映射的大小也会向上舍入到整个页面,并定位为从页面大小边界开始。