import mmap
# 创建一个文件
with open('hello.txt', 'wb') as f:
f.write(b"Hello Python!\n")
with open('hello.txt', 'r+b') as f:
# mmap基本上接收两个参数,(文件描述符,读取长度),size 为0表示读取整个文件
mm = mmap.mmap(f.fileno(), 0)
# 标准读取方式
print(mm.readline()) # prints "Hello Python!"
# 切片读取方式
print(mm[:5]) # prints "Hello"
# 切片方式改变文件内容;
# 注意size长度匹配
mm[6:] = b" world!\n"
# 使用seek定位光标到数据头,当前光标已到数据末(mm.tell()可获取当前光标)
mm.seek(0)
# 再次标准读取
print(mm.readline()) # prints "Hello world!"
# 像处理文件一样关闭mmap映射
mm.close()
输出结果
b’Hello Python!\n’
b’Hello’
b’Hello world!\n’
使用mmap完成共享内存方式的进程间通信
import mmap
import os
import time
mm = mmap.mmap(-1, 27)
mm.write(b"Original msg") # 涉及mm的读写都要记得字符串的二进制
print('write successfully')
pid = os.fork()
if pid == 0: # 子进程中
mm.seek(0)
print('Read from the mmap:')
print(mm.readline())
#以切片访问时,严格按照字符串长度
mm[12:] = b' sth from child'
mm.close()
else:
time.sleep(2)# 用sleep使子进程先执行
mm.seek(0)
print('Read from the child:')
print(mm.readline())
mm.close()
输出
write successfully
Read from the mmap:
b’Original msg\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00’
Read from the child:
b’Original msg sth from child’
当年理解fork花了不少时间,与其说父子进程,不如说兄弟进程.
从英文版入手,fork本身就是分叉的意思.运行到fork便分叉运行.这样理解自然更容易入手.
共享内存主要基于两点:
1) 子进程继承父进程的变量的副本;
2) mmap返回指向文件的指针,本来在子进程中操作的变量是不会影响父进程的.但是因为mmap代表的是一种映射关系. 犹如从fork切换到子进程时,给子进程复制了一把指向与父进程同一块内存的钥匙,虽然两把钥匙是独立的,但是凭借两把钥匙,两个进程可以在同一个内存区域上进行修改,从而完成进程间通信.
随手记: 凡是计算机的概念理解都不能脱离代码,即使API封装程度已经很高,实现一遍也会有收货.从前只是通过概念学习进程间通信,如今通过代码可以加深理解.