一.内容回顾

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

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

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

    为了合理利用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. JVM调优和深入了解性能优化

    JVM调优的本质: 并不是显著的提高系统性能,不是说你调了,性能就能提升几倍或者上十倍,JVM调优,主要调的是稳定.如果你的系统出现了频繁的垃圾回收,这个时候系统是不稳定的,所以需要我们来进行JVM调 ...

  2. python - 模块调用

    基础 调用模块常见的两种方法 import [模块名] from [模块名] import [属性/方法] 进阶用法 调用父级目录下模块 背景介绍 目录new2(b2.py)调用上级目录new1(b1 ...

  3. ByteCTF2019

    VIP 第一阶段: 先检查一下程序开的保护: 程序只开了canary和nx保护.接下来用IDA分析反编译出的伪代码 如上图,载edit函数中我们可以控制size的大小,并且程序没有做任何检查,我们再跟 ...

  4. 哪些方法可以绕过PowerShell Execution Policy?

    哪些方法可以绕过PowerShell Execution Policy? 转: https://blog.csdn.net/qq_27446553/article/details/50577296

  5. latex 封面

    latex 封面 代码: \begin{titlepage} \heiti \vspace*{64pt} \begin{center} \fontsize{48pt}{0} XX大学\\ \vspac ...

  6. Python爬虫学习第一记 (翻译小助手)

    1 # Python爬虫学习第一记 8.24 (代码有点小,请放大看吧) 2 3 #实现有道翻译,模块一: $fanyi.py 4 5 import urllib.request 6 import u ...

  7. Jack Straws(POJ 1127)

    原题如下: Jack Straws Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5555   Accepted: 2536 ...

  8. Express下ejs的视图模板引擎的建立

    写在前面 由于Express升级到4.0,将ejs的用法忽略,改为用户自定义形式,所以要引入库index.js作为引擎,来支持ejs的模板引擎(点击下载). 首先是建立一个名字叫nodeitem,引擎 ...

  9. BFC与HasLayout的理解

    1.(Block Formatting Contexts)BFC 定义 BFC(Block formatting context)直译为"块级格式化上下文".它是一个独立的渲染区域 ...

  10. SessionMiddleware源码分析

    settings.py文件中 MIDDLEWARE = [ 'django.contrib.sessions.middleware.SessionMiddleware', ] # from djang ...