懒人在思考 2018-05-28
输出
3.14159262176
管道pipe
管道是Unix进程间通信最常用的方法之一,它通过在父子进程之间开通读写通道来进行双工交流。我们通过os.read()和os.write()来对文件描述符进行读写操作,使用os.close()关闭描述符。
上图为单进程的管道
上图为父子进程分离后的管道
输出
3.14159262176
无名套接字socketpair
我们知道跨网络通信免不了要通过套接字进行通信,但是本例的多进程是在同一个机器上,用不着跨网络,使用普通套接字进行通信有点浪费。
上图为单进程的socketpair
输出
3.14159262176
OS消息队列
操作系统也提供了跨进程的消息队列对象可以让我们直接使用,只不过python没有默认提供包装好的api来直接使用。我们必须使用第三方扩展来完成OS消息队列通信。第三方扩展是通过使用Python包装的C实现来完成的。
输出
3.14159262176
systemv消息队列systemv消息队列和posix消息队列用起来有所不同。systemv的消息队列是以整数key作为名称,如果不指定,它就创建一个唯一的未占用的整数key。它还提供消息类型的整数参数,但是不支持消息优先级。
# coding: utf-8import osimport sysimport mathimport structimport posix_ipcfrom posix_ipc import Semaphorefrom posix_ipc import SharedMemory as Memorydef slice(mink, maxk):s = 0.0for k in range(mink, maxk):s += 1.0/(2*k+1)/(2*k+1) return sdef pi(n):pids = []unit = n / 10sem_lock = Semaphore("/pi_sem_lock", flags=posix_ipc.O_CREX, initial_value=1) # 使用一个信号量控制多个进程互斥访问共享内存memory = Memory("/pi_rw", size=8, flags=posix_ipc.O_CREX)os.lseek(memory.fd, 0, os.SEEK_SET) # 初始化和为0.0的double值os.write(memory.fd, struct.pack('d', 0.0)) for i in range(10): # 分10个子进程mink = unit * imaxk = mink + unitpid = os.fork() if pid > 0:pids.append(pid) else:s = slice(mink, maxk) # 子进程开始计算sem_lock.acquire() try:os.lseek(memory.fd, 0, os.SEEK_SET)bs = os.read(memory.fd, 8) # 从共享内存读出来当前值cur_val, = struct.unpack('d', bs) # 反序列化,逗号不能少cur_val += s # 加上当前进程的计算结果bs = struct.pack('d', cur_val) # 序列化os.lseek(memory.fd, 0, os.SEEK_SET)os.write(memory.fd, bs) # 写进共享内存memory.close_fd() finally:sem_lock.release()sys.exit(0) # 子进程结束sums = [] for pid in pids:os.waitpid(pid, 0) # 等待子进程结束os.lseek(memory.fd, 0, os.SEEK_SET)bs = os.read(memory.fd, 8) # 读出最终这结果sums, = struct.unpack('d', bs) # 反序列化memory.close_fd() # 关闭共享内存memory.unlink() # 销毁共享内存sem_lock.unlink() # 销毁信号量return math.sqrt(sums * 8)print pi(10000000)
输出
3.14159262176
欢迎关注我的安科网和公众号:https://home.cnblogs.com/u/Python1234/ Python学习交流
欢迎加入我的千人交流学习答疑群:125240963