共享内存(Shared Memory)是最简单的进程间通信方式,它允许多个进程访问相同的内存,一个进程改变其中的数据后,其他的进程都可以看到数据的变化。
共享内存是进程间最快速的通信方式:
`进程共享同一块内存空间。
`访问共享内存和访问私有内存一样快。
`不需要系统调用和内核入口。
`不造成不必要的内存复制。
内核不对共享内存的访问进行同步,因此程序员必须自己提供同步。
使用共享内存:
`某个进程分配内存段。
`使用这个内存段的进程要连接(attach)这个内存段。
`每个进程使用完共享内存段后,要分离(detach)这个内存段。
`在某个地方,必须有一个进程来销毁这个内存段。
Linux的内存模型:
`每个进程的虚拟内存被分为页(page)。
`每个进程维护自己的内存地址到虚拟内存页之间的映射。
`实际的数据存在于进程的内存地址上。
`尽管每个进程有自己的地址空间,多个进程的映射还是可以指向相同的页。
所有的共享内存段的大小,都是Linux内存页大小的整数倍。
Linux的页大小是4KB,不过程序员应该使用getpagesize函数来获得这个值。
分配:shmget
`第一个参数是一个整型的键,用于指定要创建的段。无关的进程可以通过指定同一个键来访问同一段共享内存。
`使用常量IPC_PRIVATE作为第一个参数,可以避免键的冲突。
`第二个参数是分配的段的大小(字节数)。实际分配的字节数会舍弃多余部分到页大小的整数倍。
`第三个参数是位标志,用来表示创建的选项。
``IPC_CREATE:表明要创建新的共享内存空间。
``IPC_EXCL:总是和上一个标志一起使用。如果指定键的共享内存段已经存在,这个标志会导致调用失败;如果没有指定这个标志,调用会返回已经占用这个键的共享内存段。
``模式标志:9个bit的标志,和系统的文件权限使用相同的标志,不过执行标志无效。这些标志定义在<sys/stat.h>中。
`返回值是新创建的或者取得的内存段的标志符(SHMID)。
连接:shmat
`第一个参数是由shmget得到的标志符(SHMID)。
`第二个参数是指向你想要映射到的本进程的地址空间的指针。如果指定NULL,Linux负责选择一个可用的地址。
===================================================
python的共享内存
python的multiprocessing模块提供两种共享内存,sharedctypes与Manager,
Manager效率较低,但支持远程共享内存。
sharedctypes效率较高,快Manager两个数量级,在多进程访问时与普通内存访问相当
结果比较如下:
test array
elapsed 0:00:00.119707
test dict
elapsed 0:00:00.152856
test shared manager list
elapsed 0:00:37.87666
test sharedctypes list in main process
elapsed 0:00:00.154170
test sharedctypes list in subprocess
elapsed 0:00:00.303328
elapsed 0:00:00.327261
elapsed 0:00:00.349312
elapsed 0:00:00.318946
elapsed 0:00:00.364301
elapsed 0:00:00.370176
elapsed 0:00:00.343588
elapsed 0:00:00.348737
代码如下:
import array from datetime import datetime, timedelta
size = 1000000 def tranverse(a): t = datetime.now() for i in range(size): a[i] print 'elapsed %s'% (datetime.now()- t)
a = array.array('i', [i for i in range(size)]) print 'test array' tranverse(a)
a = {} for i in range(size): a[i] = i print 'test dict' tranverse(a)
from multiprocessing import Manager manager = Manager() a = manager.list([i for i in range(size)]) print 'test shared manager list' tranverse(a)
from multiprocessing.sharedctypes import RawArray a = RawArray( 'i', [i for i in range(size)] ) print 'test sharedctypes list in main process' tranverse(a)
from multiprocessing import Process ps = [Process(target=tranverse, args=(a, )) for i in range(8)] print 'test sharedctypes list in subprocess' for p in ps: p.start() for p in ps: p.join()
|
参考:
http://hi.baidu.com/%B1%D8%BC%C7%CE%B4%B6%C1/blog/item/f47e99d5cf0edfc051da4b8b.html
http://blogold.chinaunix.net/u3/108641/showart_2267237.html
http://www.rainsts.net/article.asp?id=1018