一.内容回顾

  进程是计算机中最小的资源分配单位

  进程与进程之间数据隔离,执行过程异步

  为什么会出现进程的概念?

    为了合理利用cpu,提高用户体验

    多个进程是可以同时利用多个cpu的,可以实现并行的效果

  僵尸进程

  进程 状态码 z/z 僵尸进程   linux

  在主进程中控制子进程的方法

    子进程对象 = Process (target,args)  在创建的这一刻根本就没有通知操作系统

    子进程对象. start()  通知操作系统,开启子进程,异步非阻塞

    子进程对象.terminate() 通知操作系统,结束子进程,异步非阻塞

    子进程对象.is_alive()  查看子进程是否还活着

    子进程对象.join()  阻塞,直到子进程结束

    子进程对象.join(timeout = 10)  阻塞最多10s,期间子进程如果结束就结束阻塞,如果没结束10s之后也结束阻塞

# 守护进程
# 守护进程是一个子进程
# 守护进程会在主进程代码结束之后才结束
# 为什么会这样?
# 由于主进程必须要回收所有的子进程的资源
# 所以主进程必须在子进程结束之后才能结束
# 而守护进程就是为了守护主进程存在的
# 不能守护到主进程结束,就只能退而求其次,守护到代码结束了
# 守护到主进程的代码结束,意味着如果有其他子进程没有结束,守护进程无法继续守护
# 解决方案 : 在主进程中加入对其他子进程的join操作,来保证守护进程可以守护所有主进程和子进程的执行
# 如何设置守护进程
# 子进程对象.daemon = True 这句话写在start之前
# 锁
# 为什么要用锁?
# 由于多个进程的并发,导致很多数据的操作都在同时进行
# 所以就有可能产生多个进程同时操作 : 文件\数据库 中的数据
# 导致数据不安全
# 所以给某一段修改数据的程序加上锁,就可以控制这段代码永远不会被多个进程同时执行
# 保证了数据的安全
# Lock 锁(互斥锁)
# 锁实际上是把你的某一段程序变成同步的了,降低了程序运行的速度,为了保证数据的安全性
# 没有数据安全的效率都是耍流氓

信号量

# 对于锁 保证一段代码同一时刻只能有一个进程执行
# 对于信号量 保证一段代码同一时刻只能有n个进程执行
# 流量控制
# 10个进程
from multiprocessing import Semaphore

sem = Semaphore(4)
sem.acquire()
print('拿走一把钥匙1')
sem.acquire()
print('拿走一把钥匙2')
sem.acquire()
print('拿走一把钥匙3')
sem.acquire()
print('拿走一把钥匙4')
sem.release()#释放信号
sem.acquire()
print('拿走一把钥匙5')
信号量Semaphore是同时允许一定数量的线程更改数据
信号量同步基于内部计数器,每调用一次acquire(),计数器减1;每调用一次release(),计数器加1.当计数器为0时,acquire()调用被阻塞。

import time
import random
from multiprocessing import Process,Semaphore
def ktv(name,sem):
sem.acquire()
print("%s走进了ktv"%name)
time.sleep(random.randint(5,10))
print("%s走出了ktv" % name)
sem.release() if __name__ == '__main__':
sem = Semaphore(4)
for i in range(100):
p = Process(target=ktv,args = ('name%s'%i,sem))
p.start()
name1走进了ktv
name0走进了ktv
name3走进了ktv
name4走进了ktv
name1走出了ktv
name2走进了ktv
name3走出了ktv
事件Event 事件类
e = Event()
e为事件对象,事件本身就带着标识:False
wait 阻塞
它的阻塞条件是 对象标识为False
结束阻塞条件是 对象标识为True

对象的标识相关的
set 将对象的标识设置为True
clear 将对象的标识设置为False
is_set 查看对象的标识是否为True
import time
import random
from multiprocessing import Event,Process
def traffic_light(e):
print('\033[1;31m红灯亮\033[0m')
while True:
time.sleep(2)
if e.is_set(): # 如果当前是绿灯
print('\033[1;31m红灯亮\033[0m') # 先打印红灯亮
e.clear() # 再把灯改成红色
else : # 当前是红灯
print('\033[1;32m绿灯亮\033[0m') # 先打印绿灯亮
e.set() # 再把灯变绿色 def car(e,carname):
if not e.is_set():
print('%s正在等待通过'%carname)
e.wait()
print('%s正在通过'%carname) if __name__ == '__main__':
e = Event()
p = Process(target=traffic_light,args = (e,))
p.start()
for i in range(100):
time.sleep(random.randrange(0,3))
p = Process(target=car, args=(e,'car%s'%i))
p.start()
标识 控制wait是否阻塞的关键 
如何修改这个标识 : clear set
如何查看这个标识 : is_set
进程之间的数据通信 IPC
  管道 Pipe
  队列 Queue
from multiprocessing import Queue,Process

def consumer(q):
print(
'子进程 :', q.get()
) if __name__ == '__main__':
q = Queue()
p = Process(target=consumer,args=(q,))
p.start()
q.put('hello,world')

# 生产者消费者模型
import time
from multiprocessing import Queue,Process def producer(name,food,num,q):
'''生产者'''
for i in range(num):
time.sleep(0.3)
foodi = food + str(i)
print('%s生产了%s'%(name,foodi))
q.put(foodi) def consumer(name,q):
while True:
food = q.get() # 等待接收数据
if food == None:break
print('%s吃了%s'%(name,food))
time.sleep(1) if __name__ == '__main__':
q = Queue(maxsize=10)
p1 = Process(target=producer,args = ('宝元','泔水',20,q))
p2 = Process(target=producer,args = ('战山','鱼刺',10,q))
c1 = Process(target=consumer, args=('alex', q))
c2 = Process(target=consumer, args=('wusir', q))
p1.start() # 开始生产
p2.start() # 开始生产
c1.start()
c2.start()
p1.join() # 生产者结束生产了
p2.join() # 生产者结束生产了
q.put(None) # put None 操作永远放在所有的生产者结束生产之后
q.put(None) # 有几个消费者 就put多少个None
队列为空不准确
q.qsize() 队列的大小 #
q.full() 是否满了 满返回True
q.empty() 是否空了 空返回True
import  time
from multiprocessing import JoinableQueue,Process def consumer(name,q):
while True:
food = q.get()
time.sleep(1)
print('%s消费了%s'%(name,food))
q.task_done() def producer(name,food,num,q):
'''生产者'''
for i in range(num):
time.sleep(0.3)
foodi = food + str(i)
print('%s生产了%s'%(name,foodi))
q.put(foodi)
q.join() # 消费者消费完毕之后会结束阻塞
if __name__ == '__main__':
q = JoinableQueue()
p1 = Process(target=producer, args=('宝元', '泔水', 20, q))
c1 = Process(target=consumer, args=('alex', q))
c2 = Process(target=consumer, args=('wusir', q))
c1.daemon = True
c2.daemon = True
p1.start()
c1.start()
c2.start()
p1.join()
消费者每消费一个数据会给队列发送一条信息 
当每一个数据都被消费掉之后 joinablequeue的join阻塞行为就会结束
以上就是为什么我们要在生产完所有数据的时候发起一个q.join()
随着生产者子进程的执行完毕,说明消费者的数据都消费完毕了
这个时候主进程中的p1.join结束
主进程的代码结束
守护进程也结束了

进程之间的数据共享
from multiprocessing import Manager,Process,Lock
def work(d,lock):
with lock: #不加锁而操作共享的数据,肯定会出现数据错乱#{'count': 5}
d['count']-=1
# lock.acquire()#与上面意思一样
# d['count'] -= 1
# lock.release() if __name__ == '__main__':
lock=Lock()
m = Manager()
dic=m.dict({'count':100})
p_l=[]
for i in range(100):
p=Process(target=work,args=(dic,lock))
p_l.append(p)
p.start()
for p in p_l:
p.join()
print(dic)
# Manager是一个类 内部有一些数据类型能够实现进程之间的数据共享
# dict list这样的数据 内部的数字进行自加 自减 是会引起数据不安全的,这种情况下 需要我们手动加锁完成
# 因此 我们一般情况下 不适用这种方式来进行进程之间的通信
# 我们宁可使用Queue队列或者其他消息中间件 来实现消息的传递 保证数据的安全

进程池

multiprocess.Pool模块
为什么要有进程池?进程池的概念

在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程

进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。

import os
import time
from multiprocessing import Pool # 池
def func(i):
i -= 1
return i**2 # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
if __name__ == '__main__':
p = Pool(5)
ret = p.map(func,range(100)) # 自动带join
print(ret)
有了进程池,不仅可以只开有限的进程来完成无限的任务 
还可以获取程序执行的返回值
如果没有池帮助你实现功能,那么你自己能不能实现???
通过队列
# 同步方式向进程池提交任务
import time
from multiprocessing import Pool # 池
def func(i):
i -= 1
time.sleep(0.5)
return i**2 # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
if __name__ == '__main__':
p = Pool(5)
for i in range(100):
ret = p.apply(func,args=(i,)) # 自动带join 串行 同步 apply就是同步提交任务
print(ret)

# 异步方式向进程池提交任务
import time
from multiprocessing import Pool # 池
def func(i):
i -= 1
time.sleep(0.1)
print(i)
return i**2 # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
if __name__ == '__main__':
p = Pool(5)
for i in range(100):
ret = p.apply_async(func,args=(i,)) # 自动带join 异步的 apply_async异步提交任务
print(ret)
p.close() # 关闭进程池的任务提交 从此之后不能再向p这个池提交新的任务
p.join() # 阻塞 一直到所有的任务都执行完

# 异步方式向进程池提交任务并且获取返回值
import time
from multiprocessing import Pool # 池
def func(i):
i -= 1
time.sleep(1)
return i**2 # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
if __name__ == '__main__':
p = Pool(5)
l = []
for i in range(100):
ret = p.apply_async(func,args=(i,)) # 自动带join 异步的 apply_async异步提交任务
l.append(ret)
for ret in l:
print(ret.get())

# 为什么要用进程池?
# 任务很多 cpu个数*5个任务以上
# 为了节省创建和销毁进程的时间 和 操作系统的资源
# 一般进程池中进程的个数:
# cpu的1-2倍
# 如果是高计算,完全没有io,那么就用cpu的个数
# 随着IO操作越多,可能池中的进程个数也可以相应增加
# 向进程池中提交任务的三种方式
# map 异步提交任务 简便算法 接收的参数必须是 子进程要执行的func,可迭代的(可迭代中的每一项都会作为参数被传递给子进程)
# 能够传递的参数是有限的,所以比起apply_async限制性比较强
# apply 同步提交任务(你删了吧)
# apply_async 异步提交任务
# 能够传递比map更丰富的参数,但是比较麻烦
# 首先 apply_async提交的任务和主进程完全异步
# 可以通过先close进程池,再join进程池的方式,强制主进程等待进程池中任务的完成
# 也可以通过get获取返回值的方式,来等待任务的返回值
# 我们不能在apply_async提交任务之后直接get获取返回值
# for i in range(100):
# ret = p.apply_async(func,args=(i,)) # 自动带join 异步的 apply_async异步提交任务
# l.append(ret)
# for ret in l:
# print(ret.get())

# 回调函数
import os
import time
import random
from multiprocessing import Pool # 池
def func(i): # [2,1,1,5,0,0.2]
i -= 1
time.sleep(random.uniform(0,2))
return i**2 def back_func(args):
print(args,os.getpid()) if __name__ == '__main__':
print(os.getpid())
p = Pool(5)
l = []
for i in range(100):
ret = p.apply_async(func,args=(i,),callback=back_func) # 5个任务
p.close()
p.join()
# callback回调函数
# 主动执行func,然后在func执行完毕之后的返回值,直接传递给back_func作为参数,调用back_func
# 处理池中任务的返回值
# 回调函数是由谁执行的? 主进程






												

day40 Pyhton 并发编程03的更多相关文章

  1. Python并发编程03 /僵孤进程,孤儿进程、进程互斥锁,进程队列、进程之间的通信

    Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 目录 Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 1. 僵尸进程/孤儿进 ...

  2. day38 Pyhton 并发编程

    # 网络编程 # arp协议 : # 1.这是一个通过ip找mac地址的协议 # 2.由于有了socket,用户在使用网络的时候,只需要关心对方用户的ip地址就可以了 # 3.如果用户即将和这个ip进 ...

  3. day36 Pyhton 网络编程03

    一.内容回顾 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

  4. day41 Pyhton 并发编程04

    内容回顾 socket 最底层的网络通信 所有的网络通信都是基于socket     进程 什么是进程? 是操作系统的发展过程中,为了提高cpu的利用率,在操作系统同时运行多个程序的时候,为了数据的安 ...

  5. Java并发编程(03):多线程并发访问,同步控制

    本文源码:GitHub·点这里 || GitEE·点这里 一.并发问题 多线程学习的时候,要面对的第一个复杂问题就是,并发模式下变量的访问,如果不理清楚内在流程和原因,经常会出现这样一个问题:线程处理 ...

  6. day43 Pyhton 并发编程06

    一.内容回顾 线程 锁 为什么有了GIL之后还需要锁 多个线程同时操作全局变量还需要锁 当出现'非原子性操作',例如+= -= *= /= l.append(l) 原子性操作 a += 1  a= a ...

  7. day42 Pyhton 并发编程05

    一.内容回顾 # 线程 # 正常的编程界: # 进程 # 计算机中最小的资源分配单位 # 数据隔离 # 进程可以独立存在 # 创建与销毁 还有切换 都慢 给操作系统压力大 # 线程 # 计算机中能被C ...

  8. day39 Pyhton 并发编程02 后

    一.开启子进程的另一种方式 import os from multiprocessing import Process class MyProcess(Process): def __init__(s ...

  9. day39 Pyhton 并发编程02

    一.内容回顾 并发和并行的区别 并发 宏观上是在同时运行的 微观上是一个一个顺序执行 同一时刻只有一个cpu在工作 并行 微观上就是同时执行的 同一时刻不止有一个cpu在工作 什么是进程 一个运行中的 ...

随机推荐

  1. Python多行缩进反向缩进快捷键

    1.Python增加缩进快捷键:Ctrl+Alt+] 或tab键或shift+tab键 2.Python减少缩进快捷键:Ctrl+Alt+[ 

  2. Java多线程--两个线程同时对一个人的年龄进行增加和修改

    public class Thread_A extends Thread { Human human; public Thread_A(String name, Human human) { supe ...

  3. C++ Templates (2.3 类模板的局部使用 Partial Usage of Class Templates)

    返回完整目录 目录 2.3 类模板的局部使用 Partial Usage of Class Templates 2.3.1 Concepts 2.3 类模板的局部使用 Partial Usage of ...

  4. C、算法、操作系统杂记《malloc 0大小是什么行为》

    linux手册上的说明 If size is 0, then malloc() returns either NULL, or a unique pointer value that can late ...

  5. JDK13环境变量配置

    第一步:下载JDK(开发工具包) JDK分为OracleJDK和OpenJDK下面简要说明 OracleJDK 部分代码闭源.商业收费 OpenJDK 开放源码.商业免费 两者大部分代码是共用的(除闭 ...

  6. (专题四)06 matlab绘图选项卡

    绘图选项卡 例子1--选择已有变量,绘制图形 都是按照选中的先后顺序依次确定坐标, 如果要修改绘制图形 法一,利用绘图工具和停靠图形按钮 法二,命令行窗口中输入命令 >>plottools ...

  7. springboot之启动端口指定

    https://www.cnblogs.com/yaomajor/p/8616929.html

  8. golang "%p"学习记录随笔

    对于获取slice的指针地址, 通过unsafe.Pointer 和 "%p"占位符两种方式得到的地址是不同的 s := make([]int, 1) t.Log(unsafe.P ...

  9. k8s&docker面试总结

    花了大半个月对k8s&docker进行了梳理,包括之前读过的书,官方文档以及k&d在公司项目的实践等. 以下是个人对docker & k8s 面试知识点的总结: 1 docke ...

  10. 常用JVM 启动参数解析

    https://www.jianshu.com/p/a17dcef57559 https://www.cnblogs.com/zkyefei/p/9334562.html