8多任务一一进程

进程以及状态

之前说过线程,这回我们聊进程,他们有一定相似性,线程是CPU调度的基本单位,进程是资源分配的基本单位,也是线程的容器(进程包含线程)

比如我们运行了飞Q程序,打开任务管理器,就会看到飞Q在执行,还显示了CPU占用,内存占用,硬盘占用以及网络占用,所以,程序是固定不变的,进程会跟据操作系统进行系统资源分配

图1
图2

程序是静态的,但运行起来,代码加用到的资源成为进程。一个进程中包括多个线程(线程是轻量级的进程)

图3

进程运行有几个状态,比如说并发的时候,cpu核小于任务数,比如图中的3任务,1个CPU,由于CPU是轮循的,执行1的一部分,1的进程就在运行状态,这时切换到2任务,2进入运行,1之前的准备资源完毕进入就绪状态。什么时候是进入等待状态呢,比如2遇到了time.sleep这时就会进入阻塞状态,同时开始3任务的运行状态。哪个任务执行完毕就进入死亡状态。如果下次2运行到就绪状态,下次轮询到就可以到运行状态。比如突然来了4任务,那这个任务就是新建启动进入就绪状态

图4

进程基本使用

进程和线程代码又类似之处

1 导入模块import multiprocessing

2创建进程对象mulitprocessing.Process(target=xxx)

3实例对象启动start()

图5

上图创建一个进程代码,我们使用多进程来实现,这里需要提出的是,进了程序执行的是主进程,而实例对象开启了一个子进程。注意这里创建子进程必须使用if __name__=='__main__':否则会提示报错

图6

为了体现主进程和子进程在(几乎)同时运行,我们改成如上代码(的确是cpu轮询效果)

图7

Process有如上图的语法,创建时,可以传入target,args,kwargs和线程一样,可以给线程起名字,指定组。还有图中的方法

进程的名称,pid】

进程名称获取(其实是获得当前进程)

图8
图9

之前的代码加上打印当前线程,就可以看到主进程和运行的子进程

图10

如果我们对进程实例的时候加上了name参数,就会打印出指定的名字

图11

获得当前进程有pid(process id)属性获得其编号,我们可以打印出主进程和子进程的编号

图12

获得编号的另一种方法,调用os模块,os.getpid()可以获得当前进程id

获得父进程的id,仍是用os模块,os,getppid()获得父进程的id,上图子进程的父进程就是主进程

我们获得进程id有什么用,linux终端我们可以使用kill -9 进程编号  来结束进程

图13

比如上图我们杀掉子进程kill -9 34968就会有如上结果,并没运行10次

图14

我们杀掉主进程,会得到pycharm的如上提示,同样结束掉程序

进程参数传递,全局变量

子进程参数传递和子线程一致,通过args=元组,kwargs=字典   来传参

进程之间不能实现全局变量共享,如果声明,也只是将其copy一份(子进程会复制主进程资源)

图15

守护主进程

守护主进程,主进程结束时,子进程也结束

图16

我们写出如上代码,会发现主进程结束了,但是子进程还是没有结束。

我们想主进程结束子进程也跟着结束,需要使用实例属性赋值Process.daemon=True(和线程不一样,线程使用setDaemon方法),如下图

图17

另一种方法,在主进程结束前使用实例Process.terminate()结束子进程

图18

进程和线程的对比

功能上区别

图19

2使用区别

图20
图21

比如上图内存执行着网易云音乐和天天静听的2个进程,每个进程都有下载和播放的线程,下载和播放线程之间共享着歌曲读写资源,但是进程间没有资源共享,互不影响,所以进程会更稳定。

线程不能单独运行,必须存在于进程中

对比图

图22
图23
图24

选择原则

频繁创建优先线程,消耗资源小,切换速度快,大量计算使用线程,多机分布多进程,多核多线程,安全角度可能选择进程,速度角度选择线程,都满足,那就哪个熟悉拿手就行。但是cpython有GIL锁,当IO操作达到一定数量才会释放,造成多核cpu,多线程也是分时切换。

CPU密集型,进程优先,IO密集型,线程优先

消息队列一基本操作

由于进程间本身并不能共享资源,我们使用队列容器,来给多进程实现数据传递

图25

队列如上图,一段发数据,另一端取数据,放入值put,取出值get

图26

上图简单代码实现queue传入消息,实例时需要指定队列长度,上图放置完运行没问题。

图27

当我们尝试再加入一个消息时,发现程序并没有结束,其实这时是进入了阻塞状态,因为最大长度为3,新消息进入,需要一个消息发送出

图28

我们把超过队列长度的最后一个改成方法put_nowait,运行直接报错,这个方法会不阻塞等待,直接报错

图29

我们可以将数据取出来打印,会发现先放进去的先取出来

图30

如果我们想多取一个,程序就会进入阻塞状态,等待队列传入才能取出

图31

同样我们可以使用get_nowait方法,这样当读不到消息就会报错,queue.Empty提示队列已空

图32

消息队列一常见判断

图33

上次结尾列举了就几个方法,这里我们调用下,Queue的方法empty和full判断是否空满,注意方法要加括号,返回Bool值。qsize方法返回队列的消息长度值

注意仔细看图中会发现有个坑,即放满了队列后,empty返回的结果也是True

图34

看了官方文档的empty和full解释,的确也都加了not reliable不可信的解释,这是为什么呢,因为我们读取状态的时候,写入可能没有那么快,如果加入一定的延时如time.sleep可能就会使数据准确存放

Queue实现进程间的数据共享

进程通信思路:进程a写入put,进程b读取get

图35

如上图,我们编写2个进程分别从队列中读写数据,会发现读的顺序快了,结果没写入就读完了

图36

为了实现能读取成功,我们使用进程的jion方法,让写先完成,就出现如上结果,其实相当于单进程

进程池

我们为什么使用进程池,当我们创建进程数量不多时,可以用Process实例来生成,当进程数量大到千百个量级以上,我们就可以使用Pool方法创建生成多个进程的方法

Pool根据请求创建进程,初始设定进程上限,如果没到上限,有请求就继续创建,如果达到上限,就会等待池中进程有结束

图37

Pool类实例核心方法

图38

apply() 同步方式执行,池子里预先创建3个进程,比如上图3个文件拷贝,我们先启动进程1,用于拷贝文件1,结束后启动进程2,拷贝文件2,至启动进程3拷贝文件3,如果还有第四个任务,就会等进程池有进程结束,利用这个进程启动新任务(同一时间只有一个进程执行)

图39

apply_async() 异步方式 如上图三个任务,三个进程同时启动,一起完成任务,如果还有第四个任务,就会等进程池有进程结束,利用这个进程启动新任务

代码应用,模拟同步拷贝文件

图40

代码说明,使用进程池,设置进程池最大进程数,执行使用pool.apply(),apply有3个参数,func传入函数,args,kwargs之前进程实例也接触过,是用于参数传递。这里我们先不传参,在每个进程打印当前进程,会发现10个任务不是像我们想象中的1231231231这样的,其实是我修改了sleep时间,如果sleep时间长会形成类似顺序执行的结构,但是由于资源没释放资源准备等因素,进程池自身管理每个任务哪个进程来执行

一旦进程池创建,他们的pid就固定了,所以新任务来不是新创建线程,而是让空闲的进程执行新的任务

图41

我们用过同步,就会摩拳擦掌来试试异步了,我们先把上面代码apply换成apply_async来试试,哎,怎么什么结果都没有就完事啦

图42

我们怎么才能让异步实现呢,上面的问题是怎么回事,这里我们需要注意的是,异步进程池比同步进程池需要多2步操作,第一部是pool.close()这里关闭并不是不执行了,而是不再接收新的额外任务了,第二个是加上pool.join(),之前直接结束时因为使用异步,主进程就默认不会等待子进程结束,主进程结束,pool也就销毁了,于是池里的任务不会执行,我们使用join,这样主进程就会等待进程池任务都结束再结束。例中代码改慢sleep时间,会发现3个3个显示

进程池的Queue

标题即开始讲进程池间进程的通信

图43

实例方法queue=multiprocessing.Manager().Queue(3)

图44

比如我们实现个同步写入读取

图45

我们实现异步写入读取,当然还是不要忘了,close,join

图46

按照视频中代码,我们使用异步,并没有实现我们想要的功能,(各人感觉还不如充分利用queue读写的阻塞功能),这是因为pool分配资源,先准备好了读的功能,所以没读到(即使你write写在read前apply),这时我们怎么办呢

图47

apply_async异步函数会返回一个对象,可以pycharm查看源码,使用对象的wait功能,就会实现类似join的功能,其实这样也变相变成了单进程,先写完再读

案例,多进程文件复制

视频教程是使用读写进程,这里直接使用shutil.copy(src,dst)来实现

图48

这里需要注意的是,开始我尝试在进程函数内直接使用filelist,source_dir,tar_dir这几个参数,函数并没有报错,但是也没有执行下去,直接结束了,所以记得一定要把这些引用的看似全局的参数提供给子线程,

多进程版web服务器

图49

具体代码不用详解了,这里用的是封装过的代码,需要注意的是多进程引用的函数是request_handler,我们传入了new_socket(accept返回),在函数里已经close掉,但是我们多线程创建完还是得close一遍,这就是因为子进程对new_socket拷贝了一份,引用计数相当为2,当函数内close,相当于引用计数变成1,但是还没有彻底关闭new_socket,还需要再close一回

可迭代对象

为什么学习:可迭代对象-》迭代器-》生成器-》协程

图50
图51

我们可以导入collections的Iterable类,用isinstance来判断是否可迭代

图52

我们随便创建一个类对象,会发现是不可可迭代的

图53

当我们给类添加iter魔法方法,这个类的实例就是可迭代的。

所以对象所属类有__iter__方法,即是可迭代对象

迭代器和使用方法

图54

iter获得迭代器,多次使用next逐个获得迭代器元素

迭代器可以记录遍历的位置,配合next获得下个元素(如果迭代器到头,再next会引发StopIteration错误)

for循环本质,取得可迭代对象的迭代器,每次调用获得next迭代器的内容,遇到StopIteratioin异常停止

自定义迭代器需要类定义iter,next这2个魔法方法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容

  • 必备的理论基础 1.操作系统作用: 隐藏丑陋复杂的硬件接口,提供良好的抽象接口。 管理调度进程,并将多个进程对硬件...
    drfung阅读 3,541评论 0 5
  • 一. 操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式: 向下管理硬件,向上提供接口.操作系统进行...
    月亮是我踢弯得阅读 5,972评论 3 28
  • 【JAVA 线程】 线程 进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者...
    Rtia阅读 2,768评论 2 20
  • 系统编程:多任务编程 1. 线程: 可以理解成执行代码的分支,线程是执行对应的代码的 1.1 线程的工作原理: ...
    梦醒家先生阅读 989评论 2 0
  • 进程、进程的使用、进程注意点、进程间通信-Queue、进程池Pool、进程与线程对比、文件夹拷贝器-多任务 1.进...
    Cestine阅读 817评论 0 0