def write2(f):
fs = open(f, 'a+')
n = 10000
while n > 0:
fs.write('bbbbbbbbbbbbbbbb\n')
n -= 1
fs.close()
if __name__ == '__main__':
f = 'test.txt'
p1 = multiprocessing.Process(target=write1, args=(f,))
p2 = multiprocessing.Process(target=write2, args=(f,))
p1.start()
p2.start()
多进程在没有加锁的情况下,没有出现写入错误的现象。
多进程加锁的写法:
#!_*_coding:utf-8_*_
#__author__:"hkey"
import multiprocessing, sys
def write1(f, lock):
lock.acquire()
fs = open(f, 'a+')
n = 10000
while n > 0:
fs.write('aaaaaaaaaaaaaa\n')
n -= 1
fs.close()
lock.release()
def write2(f, lock):
lock.acquire()
fs = open(f, 'a+')
n = 10000
while n > 0:
fs.write('bbbbbbbbbbbbbbbb\n')
n -= 1
fs.close()
lock.release()
if __name__ == '__main__':
lock = multiprocessing.Lock()
f = 'test.txt'
p1 = multiprocessing.Process(target=write1, args=(f,lock))
p2 = multiprocessing.Process(target=write2, args=(f,lock))
p1.start()
p2.start()
个人总结:在多进程编程中,如果只是变量的计算或者cpu计算,可以不加锁,因为每个进程的地址空间都是独立的存在。
而在写入同一个文件的时候,就有必要加锁。
4. 子进程的控制
子进程是独立与主进程的存在,创建子进程时,系统fork出子进程后,就与主进程资源完全独立了,我们不单单创建完子进程就行了,还要控制子进程
的输入和输出。
subprocess模块可以让我们非常方便的启动一个子进程,然后控制其输入和输出。
子进程输出:
使用subprocess模块,在子进程中运行 ping -n 1 baidu.com
#!_*_coding:utf-8_*_
# Author: hkey
import subprocess
print('$ ping -n 1 baidu.com')
r = subprocess.call(['ping', '-n', '1', 'baidu.com'])
print('Exit code:', r)
输出结果:
$ ping -n 1 baidu.com
正在 Ping baidu.com [111.13.101.208] 具有 32 字节的数据:
来自 111.13.101.208 的回复: 字节=32 时间=22ms TTL=51
111.13.101.208 的 Ping 统计信息:
数据包: 已发送 = 1,已接收 = 1,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 22ms,最长 = 22ms,平均 = 22ms
Exit code: 0
子进程输入:
print('$nslookup')
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx\napache.org\nexit\n') # 通过调用communicate方法实现输入,这里是二进制格式。
result = output if output else err
print(result.decode('gbk'))
print('Exit code:', p.returncode)
输出结果:
# 主机dns有问题,但是输出结果完全正确的。
$nslookup
默认服务器: UnKnown
Address: 127.0.0.1
> > 服务器: UnKnown
Address: 127.0.0.1
>
Exit code: 0
5. 进程间通信
虽然子进程从主进程fork后是独立的存在,但进程之间肯定是需要通信的。python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等方式
来交换数据。
进程间通信,最典型的例子就是消费者生产者模型, 生产者生产数据,消费者消费。
#!_*_coding:utf-8_*_
# Author: hkey
from multiprocessing import Process, Queue
import os, time
def write(q):
for i in range(10):
print('process to write: %s' % os.getpid())
print('生产包子[%s]' %i)
q.put(i) # 将i上传至队列中。
time.sleep(1)
def read(q):
while True:
print('process to read: %s' % os.getpid())
values = q.get(True) # 通过get方法将队列中的数据下载,从队列中拿走一个数据就少一个数据。
print('吃掉包子[%s]' %values)
if __name__ == '__main__':
q = Queue() # 调用Queue方法生成一个队列
pw = Process(target=write, args=(q,)) # 通过进程的方式调用
pr = Process(target=read, args=(q,))
pw.start()
pr.start()
pw.join()
pr.terminate() # 因为read()是死循环,需要通过terminate()方法关闭。
输出结果: