python网络编程--进程(方法和通信),锁, 队列,生产者消费者模型
- 1.进程
- 正在进行的一个过程或者说一个任务.负责执行任务的是cpu
- 进程(Process:
- 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。我们自己在python文件中写了一些代码,这叫做程序,运行这个python文件的时候,这叫做进程。
- 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
- 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
- Process([group [, target[, name [, args [,kwargs]]]]])由该类实例化的对象,可用来开启一个子进程
- 开启进程:
- from multiprocess import Process
- p = Process(target=方法名)
参数介绍:
- group未使用,值始终为None
- target表示调用对象,即子进程要执行的任务
- args表示调用对象的位置参数元组, args(1,)
- kwargs表示调用对象的字典,kwargs = {'name':'bob'}
- name为子进程的名称
- 1.进程的创建方法,两种(引入multiprocess模块的Process模块)
- 1).函数的方式
- import time
- from multiprocessing import Process
- def f1():
- time.sleep(3)
- print('xxxx')
- def f2():
- time.sleep(3)
- print('ssss')
- # f1()
- # f2()
- #windows系统下必须写main,因为windows系统创建子进程的方式决定的,开启一个子进程,这个子进程 会copy一份主进程的所有代码,并且机制类似于import引入,这样就容易导致引入代码的时候,被引入的代码中的可执行程序被执行,导致递归开始进程,会报错
- if __name__ == '__main__': #
- # p1 = Process(target=f1,)
- p2 = Process(target=f2,)
- # p1.start()
- p2.start()
- 2).面向对象的创建方式
- from multiprocessing import Process
- class MyProcess(Process):
- def __init__(self,n):
- super().__init__() #别忘了执行父类的init
- self.n = n
- def run(self):
- print('这里是参数%s' %self.n)
- if __name__ == '__main__':
- p1 = MyProcess('我的进程')
- p1.start()
2.for循环创建进程
- import time
- from multiprocessing import Process
- def f1(i):
- time.sleep(3)
- print(i)
- if __name__ == '__main__':
- for i in range(20):
- p1 = Process(target=f1,args=(i,))
- p1.start()
3.进程的两种传参方式
- from multiprocessing import Process
- #演示两种传参方式
- def f1(n):
- print(n)
- if __name__ == '__main__':
- # p1 = Process(target=f1,args=('参数1',)) #创建进程对象
- p1 = Process(target=f1,kwargs={'n':'参数2'}) #创建进程对象
- p1.start() #给操作系统发送了一个创建进程的信号,后续进程的创建都是操作系统的事儿了
- 2.进程的其他方法(Process)
1.join方法- 在主进程运行过程中如果想并发的执行其他任务,我们可以开启子进程,此时主进程的任务与子进程的任务分为两种情况
- 情况1:
在主进程的任务与子进程的任务彼此独立的情况下,主进程的任务先执行完毕之后,主进程还需要等待子进程执行完毕,然后统一回收资源
情况2:
如果主进程的任务在执行到某一个阶段时,需要等待子进程执行完毕后才能继续执行,就需要有一种机制能够让主进程检测子进程是否运行完毕,在子进程执行完毕后才继续执行,否则一直在原地阻塞,这就是join方法的作用
示例:
- import time
- from multiprocessing import Process
- def f1():
- time.sleep(2)
- print('xxxx')
- def f2():
- time.sleep(2)
- print('ssss')
- # f1()
- # f2()
- if __name__ == '__main__':
- p1 = Process(target=f1,)
- p1.start()
- p1.join() # 主进程等待子进程运行完才继续执行
- print('开始p2拉')
- p2 = Process(target=f2,)
- p2.start()
- p2.join()
- print('我要等了...等我的子进程...')
- # time.sleep(3)
- print('我是主进程!!!')
- 2.Process类中其他的方法
- 方法:
- p.start():启动进程,并调用该子进程中的p.run()
- p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
- p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
- p.is_alive():如果p仍然运行,返回True
- p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
- 属性:
- p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
- p.name:进程的名称
- p.pid:进程的pid
- p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
- p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
- import time
- import os
- from multiprocessing import Process
- def f1():
- print('子进程的pid',os.getpid())
- print('子进程的父进程的pid',os.getppid())
- print('aaa')
- def f2():
- print('bbb')
- if __name__ == '__main__':
- p1 = Process(target=f1,name='宝宝1')
- p2 = Process(target=f2,)
- p1.start()
- p2.start()
- print(p1.name)
- print('子进程的pid',p1.pid)
- print('父进程的id',os.getpid())
- #进程的其他方法
- def f1():
- time.sleep(5)
- print('子进程1号')
- if __name__ == '__main__':
- p = Process(target=f1,)
- p.start()
- print(p.is_alive()) #判断子进程是否还活着,是否还在运行
- p.terminate() #给操作系统发送一个结束进程的信号
- time.sleep(0.5)
- print(p.is_alive())
验证进程之间的空间是相互隔离的:
- from multiprocessing import Process
- num = 100
- def f1():
- global num
- num = 3
- print('子进程中的num',num)
- print('>>>>>',num)
- if __name__ == '__main__':
- p = Process(target=f1,)
- p.start()
- p.join()
- print('主进程中的num',num)
- 3.守护进程
主进程结束,守护进程也跟着结束,对于进程来说,主进程代码结束就是结束- p.daemon:
默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随即终止,并且设定为True之后,p不能创建字节的新进程,必须在p.start()之前设置
- 1.守护进程会在主进程代码执行结束后就终止
- 2.守护进程内再无法开启子进程,否则抛出异常:
- AssertionError: daemonic processes are not allowed to have children
- 如果我们有两个任务需要并发执行,那么开一个主进程和一个子进程分别去执行就可以了,如果子进程的任务在主进程任务结束后就没有存在的必要了,那么该子进程应该在开启前就被设置成守护进程.主进程代码运行结束,守护进程随即终止
- 守护进程示例:
- import time
- from multiprocessing import Process
- def f1():
- time.sleep(3)
- print('xxxx')
- def f2():
- time.sleep(5)
- print('普通子进程的代码')
- if __name__ == '__main__':
- p = Process(target=f1,)
- p.daemon = True #将该进程设置为守护进程,必须写在start之前,意思如果我的主进程代码运行结束了,你这个子进程不管运行到什么地方,都直接结束
- p.start()
- #开启一个普通的子进程来验证一下守护进程的结束只和主进程的代码运行结束有关系,而整个程序的结束需要主进程和普通的子进程的代码都运行结束才结束
- p2 = Process(target=f2,)
- p2.start()
- #等待2号普通进程的结束,才继续执行下面主进程中的代码
- # p2.join()
- #守护进程会跟跟着父进程的代码运行结束,就结束
- print('主进程结束')
4.进程锁/互斥锁
进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端没有问题.但共享带来竞争,进而导致错乱,这时就需要加锁处理.互斥锁的原理就是把病发改成串行,降低了效率,但保证了数据安全不错乱.
- 互斥锁与join()
join()将一个任务整体串行,互斥锁的好处就是可以将一个任务中的某一段代码串行.
- loc = Lock()
- #第一种方式
- def func(loc):
- loc.acquire()
- 需要锁的代码
- loc.release()
- #第二种方式
- With loc:
- 需要锁的代码
- 5.进程间的数据共享
- 通过引入manager,结合Lock来实现进程之间的数据共享
- 1.使用for循环来创建子进程
- import time
- from multiprocessing import Process
- def f1():
- time.sleep(0.5)
- print('xxx')
- if __name__ == '__main__':
- p_list = []
- #for循环创建子进程,并且完成主进程等待所有子进程执行结束,才继续执行
- for i in range(10):
- p = Process(target=f1,)
- p.start()
- p_list.append(p)
- p.join()
- # for pp in p_list:
- # pp.join()
- print('主进程结束')
2.数据共享
为了保证进程间使用数据的安全,我们对数据处理时经常这样:
- a = 10
- tmp = a
- tmp -= 1
- a = tmp
- a -= 1 # a = a - 1
示例:
- def f1(m_d,l2):
- # m_d['num'] -= 1 #
- with l2:
- # l2.acquire()
- tmp = m_d['num']
- tmp -= 1
- time.sleep(0.1)
- m_d['num'] = tmp
- # l2.release()
- if __name__ == '__main__':
- m = Manager()
- l2 = Lock()
- m_d = m.dict({'num':100})
- p_list = []
- for i in range(10):
- p = Process(target=f1,args=(m_d,l2))
- p.start()
- p_list.append(p)
- [pp.join() for pp in p_list]
- print(m_d['num'])
- 6.队列
- 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种消息之间都是使用消息传递的
- 1.创建队列的类(底层就是管道和锁定的方式实现)
- Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递
- 2.参数介绍:
maxsize是队列中允许的最大项数,省略则无大小限制- 需要明确:
1.队列中存放的是消息而非大数据
2.队列占用的是内存空间,因而maxsize即便是无大小限制也受限于内存大小- 3.主要方法介绍:
q.put()方法用来插入数据到队列中
q.get()方法可以从队列读取并且删除一个元素
- q = Queue(5)
- q.put() #满了会等待
- q.get() #没有数据了会等待
- q.qsize()
- q.empty() 不可靠
- q.full()不可靠
- q.get_nowait() #不等待,但是报错
- q.put_nowait() #不等待,但是报错
- 基于队列的进程间通信
- from multiprocessing import Process,Queue
- def f1(q):
- q.put('约吗?')
- if __name__ == '__main__':
- q = Queue(3)
- p = Process(target=f1,args=(q,))
- p.start()
- son_p_msg = q.get()
- print('来自子进程的消息:',son_p_msg)
- 7.生产者消费者模型
1.程序中有两类角色
一类负责生产数据(生产者)
一类负责处理数据(消费者)- 2.引入生产者消费者模型为了解决的问题是
平衡生产者与消费者之间的速度差
程序解开耦合- 3.如何实现生产者消费者模型
生产者<--->队列<--->消费者- 通过队列实现一个生产者<--->消费者模型,基于joinnamlequeue的在下面,这里只是呈现基本模型:
- 生产包子---> 吃包子
- import time
- from multiprocessing import Process,Queue
- #生产者
- def producer(q):
- for i in range(10):
- time.sleep(0.7)
- s = '大包子%s号'%i
- print(s+'新鲜出炉,拿去用')
- q.put(s)
- def consumer(q):
- while 1:
- time.sleep(1)
- baozi = q.get()
- print(baozi+'被吃了')
- if __name__ == '__main__':
- q = Queue(10)
- pro_p = Process(target=producer,args=(q,))
- con_p = Process(target=consumer,args=(q,))
- pro_p.start()
- con_p.start()
8.进程队列:JoinableQueue([maxsize])
这就像一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理.通知进程是使用共享的信号和条件变量来实现的
- maxsize是队列中允许最大项数,省略则无大小限制
- q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理.如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
- q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理.阻塞将持续到队列中的每个项目均
- 调用q.task_done()方法为止
基于JoinableQueue来实现生产者消费者模型:
- import time
- from multiprocessing import Process,Queue,JoinableQueue
- #生产者
- def producer(q):
- for i in range(10):
- time.sleep(0.2)
- s = '大包子%s号'%i
- print(s+'新鲜出炉,拿去用')
- q.put(s)
- q.join() #就等着task_done()信号的数量,和我put进去的数量相同时,才继续执行
- print('所有的任务都被处理了,继续潜行吧骚年们')
- def consumer(q):
- while 1:
- time.sleep(0.5)
- baozi = q.get()
- print(baozi+'被吃了')
- q.task_done() #给队列发送一个取出的这个任务已经处理完毕的信号
- if __name__ == '__main__':
- # q = Queue(30)
- q = JoinableQueue(30) #同样是一个长度为30的队列
- pro_p = Process(target=producer,args=(q,))
- con_p = Process(target=consumer,args=(q,))
- pro_p.start()
- con_p.daemon = True
- con_p.start()
- pro_p.join()
- print('主进程结束')
python网络编程--进程(方法和通信),锁, 队列,生产者消费者模型的更多相关文章
- python并发编程之多进程(二):互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型
一,互斥锁,同步锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 竞争带来的结果就是错乱,如何控制,就是加锁处理 part1:多个进程共享同一打印终 ...
- python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))
昨日内容回顾 python中启动子进程并发编程并发 :多段程序看起来是同时运行的ftp 网盘不支持并发socketserver 多进程 并发异步 两个进程 分别做不同的事情 创建新进程join :阻塞 ...
- python开发进程:互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型
一,互斥锁,同步锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 竞争带来的结果就是错乱,如何控制,就是加锁处理 part1:多个进程共享同一打印终 ...
- day 28 :进程相关,进程池,锁,队列,生产者消费者模式
---恢复内容开始--- 前情提要: 一:进程Process 1:模块介绍 from multiprocessing import Process from multiprocessing impo ...
- 5 并发编程-(进程)-队列&生产者消费者模型
1.队列的介绍 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的 创建队列的类(底层就是以管道和锁定的方式实现 ...
- 进程部分(IPC机制及生产者消费者模型)和线程部分
进程部分 一:进程间通信IPC机制:由于进程之间的内存空间是相互隔离的,所以为了进程间的通信需要一个共享的内存空间, 但是共享带来的问题是数据在写的时候就不安全了,所以需要一种机制既有能共享的内存 空 ...
- 线程高级篇-Lock锁实现生产者-消费者模型
Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...
- POSIX信号量与互斥锁实现生产者消费者模型
posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...
- python网络编程-进程锁
一:进程锁的作用 进程锁是防止多进程并发执行在屏幕打印的时候,其他进程也输出数据到屏幕,而出现混乱现象. 比如:进程池中很多进程会向同一个日志文件中打印日志 二:代码 # -*- coding:utf ...
随机推荐
- ADO 缓存更新
if (ADOQuery1->UpdateStatus() == usUnmodified) return; ADOQuery1->UpdateBatch(arAll); Update ...
- FDQuery sqlserver 临时表
用FDQuery执行创建临时表,查不到临时表,用ADOQuery和BDEQuery均正常,比较发现用ADOQuery执行的时候只有SQL没有调用sql的系统存储过程sp_prepexec. 是fdqu ...
- MySQL GTID (二)
MySQL GTID 系列之二 三.在线将GTID转化为传统模式 环境见上篇系列文章 关闭GTID,不用停止服务,不影响线上业务 3.1 关闭GTID复制,调整为传统复制 #SLVAE实例上停止复制 ...
- c#正则获取html里面a标签href的值
获取单个a中href的值: string str = "<a href=\"http://www.itsve.com\">下载</a>" ...
- 迷你MVVM框架 avalonjs 沉思录 第1节 土耳其开局
#cnblogs_post_body p{ text-indent:2em; margin-top: 1em; } 正如一切传说的开端那样,有一远古巨神开天辟地,然后就是其他半神喧宾夺主.我们对最巨贡 ...
- A*—java代码
import java.util.ArrayList; // A*算法寻路 public class AStar2 { public static final int[][] maps = { {0, ...
- Simple Style
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x ...
- for 续9
-------siwuxie095 for 拾遗: 一: for 语句里,do 后面一般会有括号,有括号就是复合语句, 假如需要用到括号里的变量,就需要 ...
- 利用WKWebView实现js与OC交互注意事项
最近在写一些关于wkwebview的一些代码,发现了几点心得,记录一下. 1.js调用OC 我是利用wkwebview进行的开发实现,主要代码有三部分 1.向config注入OC对象 [config. ...
- springMVC入门程序。使用springmvc实现商品列表的展示。
1.1 开发环境 本教程使用环境: Jdk:jdk1.7.0_72 Eclipse:mars Tomcat:apache-tomcat-7.0.53 Springmvc:4.1.3 1.2 需求 使用 ...