Python 网络与并发编程(三)

进程Process

拥有自己独立的堆和栈,既不共享堆,也不共享栈,进程由操作系统调度;进程切换需要的资源很最大,效率低。

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。

优势:

1 可以使用计算机多核,进行任务的并行执行,提高执行效率
2 运行不受其他进程影响,创建方便
3 空间独立,数据安全

劣势

进程的创建和删除消耗的系统资源较多

进程的创建方式(方法模式)

Python的标准库提供了个模块: multiprocessing
创建进程后,使用start()启动进程

#coding=utf-8
# 方法包装-多进程实现
from multiprocessing import Process
import os
from time import sleep
def func1(name):
	print("当前进程ID:",os.getpid())
	print("父进程ID:",os.getppid())
	print(f"Process:{name} start")
	sleep(3)
	print(f"Process:{name} end")
if __name__ =="__main__":
	print("当前进程ID:",os.getpid())
	# 创建进程
	p1 = Process(target=func1, args=('p1',))
	p2 = Process(target=func1, args=('p2',))
	p1.start()
	p2.start()

当前进程ID: 15256
当前进程ID: 4888
当前进程ID: 11388
父进程ID: 15256父进程ID: 15256
Process:p2 start
Process:p1 start
Process:p1 end
Process:p2 end

进程的创建方式(继承Process类)

和使用Thread 类创建子线程的方式非常类似,使用 Process 类创建实例化对象,其本质是调用该类的构造方法创建新进程。Process类的构造方法格式如下:

def __init__(self,group=None,target=None,name=None,args=(),kwargs={})

其中,group :该参数未进行实现,不需要传参;target :为新建进程指定执行任务,也就是指定一个函数;name :为新建进程设置名称;args :为 target 参数指定的参数传递非关键字参数;kwargs :为 target 参数指定的参数传递关键字参数。

from multiprocessing import Process
from time import sleep
class MyProcess(Process):
	def __init__(self, name):
		Process.__init__(self)
		self.name = name
	def run(self):
		print(f"Process:{self.name} start")
		sleep(3)
		print(f"Process:{self.name} end")
if __name__ == "__main__":
	#创建进程
	p1 = MyProcess("p1")
	p2 = MyProcess("p2")
	p1.start()
	p2.start()

Process:p1 start
Process:p2 start
Process:p2 end
Process:p1 end

Queue实现进程间通信

前面讲解了使用 Queue 模块中的 Queue 类实现线程间通信,但要实现进程间通信,需要使用 multiprocessing 模块中的 Queue 类。
简单的理解 Queue 实现进程间通信的方式,就是使用了操作系统给开辟的一个队列空间,各个进程可以把数据放到该队列中,当然也可以从队列中把自己需要的信息取走。


from multiprocessing import Process,Queue
class MyProcess(Process):
	def __init__(self,name,mq):
		Process.__init__(self)
		self.name = name
		self.mq = mq
	def run(self):
		print("Process:{}start".format(self.name))
		print('--------------',self.mq.get(),'-------------')
		self.mq.put(self.name)
		print("Process:{}end".format(self.name))
if __name__ == '__main__':
	# 创建进程列表
	t_list = []
	mq = Queue()
	mq.put('1')
	mq.put('2')
	mq.put('3')
		# 循环创建进程
	for i in range(3):
		t = MyProcess('p{}'.format(i),mq)
		t.start()
		t_list.append(t)
		# 等待进程结束
	for t in t_list:
		t.join()
		print(mq.get())
		print(mq.get())
		print(mq.get())

Process:p1start
Process:p2start
Process:p0start--------------
1 -------------
-------------- 2 -------------
-------------- 3 -------------
Process:p1end
Process:p0endProcess:p2end
p1
p0
p2

Pipe实现进程间通信

Pipe 直译过来的意思是“管”或“管道”,和实际生活中的管(管道)是非常类似的

Pipe方法返回(conn1, conn2)代表一个管道的两个端。

#coding=utf-8
import multiprocessing
from time import sleep
def func1(conn1):
	sub_info = "Hello!"
	print(f"进程1--{multiprocessing.current_process().pid}发送数据:{sub_info}")
	sleep(1)
	conn1.send(sub_info)
	print(f"来自进程2:{conn1.recv()}")
	sleep(1)
def func2(conn2):
	sub_info = "你好!"
	print(f"进程2--{multiprocessing.current_process().pid}发送数据:{sub_info}")
	sleep(1)
	conn2.send(sub_info)
	print(f"来自进程1:{conn2.recv()}")
	sleep(1)
if __name__ == '__main__':
# 创建管道
	conn1, conn2 = multiprocessing.Pipe()
	# 创建子进程
	process1 =	multiprocessing.Process(target=func1, args=	(conn1,))
	process2 =	multiprocessing.Process(target=func2, args=	(conn2,))
	# 启动子进程
	process1.start()
	process2.start()

进程2–15904发送数据:你好!进程1–6436发送数据:Hello!
来自进程2:你好!来自进程1:Hello!

Manager管理器

管理器提供了一种创建共享数据的方法,从而可以在不同进程中共享。


#coding=utf-8
from multiprocessing import Process,current_process
from multiprocessing import Manager
def func(name,m_list,m_dict):
	m_dict['name'] = 'zhangsan'
	m_list.append('你好')
if __name__ == "__main__":
	with Manager() as mgr:
		m_list = mgr.list()
		m_dict = mgr.dict()
		m_list.append('Hello!!')
		#两个进程不能直接互相使用对象,需要互相传递
		p1 = Process(target=func,args=('p1',m_list,m_dict))
		p1.start()
		p1.join() #等p1进程结束,主进程继续执行
		print(m_list)
		print(m_dict)

[‘Hello!!’, ‘你好’]
{‘name’: ‘zhangsan’}

进程池(Pool)

类/方法功能参数
Pool(processes)创建进程池对象processes表示进程池中有多少进程
pool.apply_async(func,args,kwds)异步执行;将事件放入到进程池队列func 事件函数 args 以元组形式给func传参kwds 以字典形式给func传参 返回值:返回一个代表进程池事件的对象,通过返回值的get方法可以得到事件函数的返回值
pool.apply(func,args,kwds)同步执行;将事件放入到进程池队列func 事件函数 args 以元组形式给func传参kwds 以字典形式给func传参
pool.close()关闭进程池
pool.join()回收进程池
pool.map(func,iter)类似于python的map函数,将要做的事件放入进程池func 要执行的函数 iter 迭代对象
#coding=utf-8
from multiprocessing import Pool
import os
from time import sleep
def func1(name):
	print(f"当前进程的ID:{os.getpid()},{name}")
	sleep(2)
	return name
def func2(args):
	print(args)
if __name__ == "__main__":
	pool = Pool(5)
	pool.apply_async(func = func1,args=('z1',),callback=func2)
	pool.apply_async(func = func1,args=('z2',),callback=func2)
	pool.apply_async(func = func1,args=('z3',),callback=func2)
	pool.apply_async(func = func1,args=('z4',))
	pool.apply_async(func = func1,args=('z5',))
	pool.apply_async(func = func1,args=('z6',))
	pool.apply_async(func = func1,args=('z7',))
	pool.apply_async(func = func1,args=('z8',))
	pool.close()
	pool.join()

当前进程的ID:18736,z1
当前进程的ID:17316,z2
当前进程的ID:12900,z3
当前进程的ID:10120,z4
当前进程的ID:1680,z5
当前进程的ID:10120,z6
当前进程的ID:17316,z7
当前进程的ID:1680,z8
z2
z1
z3

  • 47
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_44006060

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值