进程是计算机资源分配的最小单位;一个进程可以有多个线程,同一个进程中线程共享资源
进程和进程之间是相互隔离的
Python中通过多进程可以利用CPU多核,使用于计算密集型操作
1.1进程
import multiprocessing
def task(agr):
pass
def run():
p=multiprocessing.Process(target=task,args=('123',))
p.start()
if __name__=="__main__":
run()
要求:启动代码要放在if name=="main": 下
multiprocessing创建进程的方式
fork 【几乎开拷贝所有的父进程资源】【支持文件对象/线程锁传参】【unix】【任意位置开始】【快】
spawn【run参数传必备资源】【不支持文件对象/线程锁传参】【unix,win】【main代码块开始】【慢慢】
fokserver【run参数传必备资源】【不支持文件对象/线程锁传参】【部分unix】【main代码块开始】
import multiprocessing
import threading
import time
def func():
with lock:
print(666)
time.sleep(1)
def task():
#子进程 copy父进程资源,包括进程锁
print(111)
for i in range(10):
t=threading.Thread(target=func)
t.start()
time.sleep(10)
#子进程的主线程被锁,在锁释放前无法切换线程
lock.release()
if __name__=="__main__":
multiprocessing.set_start_method("fork")
name=[]
lock = threading.RLock()##加锁
lock.acquire()
p=multiprocessing.Process(target=task)
p.start()
锁是Python提供给我们能够自行操控线程切换的一种手段,使用锁可以让线程的切换变的有序。
1.2常见功能
进程的常见方法:
p.start():当前进程准备就绪,等待被cpu调度(工作单元就是进程中的线程)
p.jion():等待当前进程的任务执行完毕后再向下继续执行
import multiprocessing
import time
from multiprocessing import Process
def task():
time.sleep(10)
print('执行中。。。。。。。')
if __name__=="__main__":
multiprocessing.set_start_method('spawn')
p=Process(target=task)
p.start()
p.join()
print("执行完毕")
p.daemon=布尔值,守护进程(必须放在start之前)
p.daemon=Ture,设置为守护进程,主进程结束子进程
p.daemon=False,设置为非守护进程,主进程等待子进程
import multiprocessing
import time
from multiprocessing import Process
def task():
time.sleep(10)
print('执行中。。。。。。。')
if __name__=="__main__":
multiprocessing.set_start_method('spawn')
p=Process(target=task)
p.daemon=False
p.start()
# p.join()
print("执行完毕")
进程名字的设置与获取
设置:p.name='创建的子进程1'
获取:multiprocessing.current_process().name
获取当前进程id:os.getpid()
获取父进程id:os.getppid()
获取当前进程的线程:threading.enumerate()
import multiprocessing
import time
from multiprocessing import Process
import threading
def func():
time.sleep(3)
def task():
for i in range(10):
t=threading.Thread(target=func)
t.start()
time.sleep(1)
print('线程个数',len(threading.enumerate()))
print('当前进程的名字',multiprocessing.current_process().name)
if __name__=="__main__":
multiprocessing.set_start_method('spawn')
p=Process(target=task)
p.name='创建的子进程1'
p.start()
print("执行完毕")
自定义进程类,直接将子进程的任务写都run方法中
import multiprocessing
import time
from multiprocessing import Process
import os
class MyPorcess(Process):
def run(self):
print('进程',self._args,os.getpid())
if __name__=="__main__":
print(os.getpid())
multiprocessing.set_start_method("spawn")
p=MyPorcess(args=('123',))
p.start()
print('end')
获取cpu个数,程序一般创建多少个进程(利用cpu的多核优势)
import multiprocessing
multiprocessing.cpu_count()
2.进程间的数据共享
进程是资源分配的最小单元,每个进程间都维护自己独立的数据,不共享
import multiprocessing
def task(data):
data.append(324)
if __name__ == "__main__":
data_list = []
p = multiprocessing.Process(target=task, args=(data_list,))
p.start()
p.join()
print('end', data_list) #
2.1共享
通过value和array
通过Manager进行管理
import multiprocessing
def task(d, l):
d[1] = 1
d['2'] = 2
d[0.25] = None
l.append(123)
if __name__ == "__main__":
with multiprocessing.Manager() as manger:
d = manger.dict()
l = manger.list()
p = multiprocessing.Process(target=task, args=(d, l))
p.start()
p.join()
print(d) #
print(l) #
# {1: 1, '2': 2, 0.25: None}
# [123
2.2 交换
multiprocessing supports two types of communication channel between process
Queues
The Queue class is an near clone of queue.Queue,For example
import multiprocessing
import time
def task(q):
for i in range(10):
q.put(i)
if __name__ == "__main__":
queue=multiprocessing.Queue()
p = multiprocessing.Process(target=task, args=(queue,))
p.start()
p.join()
print('main process')
time.sleep(1)
print(queue.get())
print(queue.get())
print(queue.get())
print(queue.get())
print(queue.get())
print(queue.get())
print(queue.get())
print(queue.get())
print(queue.get())
# main process
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
ps:实现方法:
输入:queue.put()
输入:queue.get()
Pipes
import multiprocessing
import time
def task(conn):
time.sleep(1)
conn.send([111,222,333,444])
data=conn.recv()
print('subprocess recive:',data)
time.sleep(2)
if __name__ == "__main__":
parent_conn,child_conn=multiprocessing.Pipe()
p = multiprocessing.Process(target=task, args=(child_conn,))
p.start()
# p.join()
info = parent_conn.recv()#阻塞
print('main process recive',info)
parent_conn.send(666)
# main process recive [111, 222, 333, 444]
# subprocess recive: 666
3. 进程锁
为了防止多个进程抢占式去做某些操作(同一个资源)的时候,出现操作问题,可以通过进程锁来控制进程的切换
import multiprocessing
import time
def task(n):
n.value = n.value + 1
if __name__ == "__main__":
num = multiprocessing.Value('i', 0)
for i in range(100):
p = multiprocessing.Process(target=task, args=(num,))
p.start()
# time.sleep(3)
print(num.value)
进程锁:
import multiprocessing
import time
def task(lock):
print('start')
lock.acquire()
with open('f1.txt', mode='r', encoding='utf-8') as f:
current_n = int(f.read())
print(current_n)
time.sleep(1)
print('doing')
current_n -= 1
with open('f1.txt', mode='w', encoding='utf-8') as f:
f.write(str(current_n))
lock.release()
if __name__ == "__main__":
multiprocessing.set_start_method('spawn')
lock = multiprocessing.RLock()
process_list = []
for i in range(10):
p = multiprocessing.Process(target=task, args=(lock,))
p.start()
process_list.append(p)
# 'spawn'特殊处理
for item in process_list:
item.join()
print('main process end')
4.进程池
import time
from concurrent.futures import ProcessPoolExecutor
def task(num):
print('dong', num)
time.sleep(2)
if __name__ == "__main__":
pool = ProcessPoolExecutor(4)
for i in range(10):
pool.submit(task, i)
import multiprocessing
import time
from concurrent.futures import ProcessPoolExecutor
def task(num):
print('dong', num)
time.sleep(2)
return num
def done(res):
print(multiprocessing.current_process())
time.sleep(1)
print(res.result())
time.sleep(1)
if __name__ == "__main__":
pool = ProcessPoolExecutor(4)
for i in range(10):
pool.submit(task, i).add_done_callback(done)##done有mainProcess处理,线程池中由subthreading处理
pool.shutdown(True)
print('main end')
ps:如果在进程池中使用进程锁,字需要基于Manager中的Lock和Rlock来实现
import multiprocessing
import time
from concurrent.futures import ProcessPoolExecutor
def task(lock, ):
print('start')
with lock:
# print('doing', lock)
time.sleep(2)
with open('f1.txt', mode='r', encoding='utf=8') as f:
num = int(f.read())
num -= 1
with open('f1.txt', mode='w', encoding='utf=8') as f:
f.write(str(num))
if __name__ == "__main__":
pool = ProcessPoolExecutor(4)
# lock_obj=multiprocessing.RLock()#不能使用
lock_obj = multiprocessing.Manager().RLock()
for i in range(10):
pool.submit(task, lock_obj) ##done有mainProcess处理,线程池中由subthreading处理
pool.shutdown(True)
print('main end')
5.协程
协程:可以称之为微线程,是一种用户态内的上下文的切换技术
greenlet
pip insatll greenlet
from greenlet import greenlet
def fun1():
print(1) #第一步:print 1
gr2.switch()#第2步:切换到func2
print(2)#第5步:print 2
gr2.switch()#第6步:切换到func2从上一次执行的位置继续向后执行
def fun2():
print(3)#第3步:print 3
gr1.switch()#第4步:切换到func1,从上一次执行的位置继续向后执行
print(4)#第7步:print4
gr1 = greenlet(fun1)
gr2 = greenlet(fun2)
gr1.switch()#第0步执行gr1
1
3
2
4
yield
def fun1():
yield 1
yield from fun2()
yield 2
def fun2():
yield 3
yield 4
f=fun1()
for i in f:
print(i)
上述两种方式均可实现协程,但是这种编码方式没有意义
来回的切换,会使程式变的更慢
协程有意义
不是手动切换,而是遇到IO操作时自动切换
asynico,async,等模块,内部基于协程并且遇到IO操作请求自动切换
import asyncio
async def fun1():
print(1)
await asyncio.sleep(2)#线程等待2s
print(2)
async def fun2():
print(3)
await asyncio.sleep(2)#线程等待2s
print(4)
task=[
asyncio.ensure_future(fun1()),
asyncio.ensure_future(fun2())
]
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))
结果:
1
3
2
4
通过以上内容,在处理IO请求时,协程通过一个线程就可以实现并发的操作