一: 进程的概念:(Process)

进程就是正在运行的程序,它是操作系统中,资源分配的最小单位.

资源分配:分配的是cpu和内存等物理资源

进程号是进程的唯一标识

同一个程序执行两次之后是两个进程

进程和进程之间的关系: 数据彼此隔离,通过socket通信

二:并行和并发

并发:一个cpu同一时间不停执行多个程序

并行:多个cpu同一时间不停执行多个程序

三:cpu的进程调度方法

# 先来先服务fcfs(first come first server):先来的先执行

# 短作业优先算法:分配的cpu多,先把短的算完

# 时间片轮转算法:每一个任务就执行一个时间片的时间.然后就执行其他的.

# 多级反馈队列算法

 

越是时间长的,cpu分配的资源越短,优先级靠后

越是时间短的,cpu分配的资源越多

 

### 进程三状态图

 

(1)就绪(Ready)状态

只剩下CPU需要执行外,其他所有资源都已分配完毕 称为就绪状态。

(2)执行(Running)状态

cpu开始执行该进程时称为执行状态。

(3)阻塞(Blocked)状态

由于等待某个事件发生而无法执行时,便是阻塞状态,cpu执行其他进程.例如,等待I/O完成input、申请缓冲区不能满足等等。

 

这三个在下面学习的内容中是一起掺杂在一起的

(1)获取进程号

使用os.getpid()  获取子进程号

使用os.getppid()  获取父进程号

#例:

  1. import os, time
  2.  
  3. # 获取子进程[当前进程]的id号
  4. res1 = os.getpid()
  5. print(res1)
  6. # 获取父进程的id号
  7. res2 = os.getppid()
  8. print(res2)
  9. # linux Process 底层利用的是fork来创建进程的,而fork在windows里并不支持.

#如果在编辑器上运行可知,父进程号是不变得,子进程号是改变的,因为父进程号是编辑器运行的进程号,二子进程号是这个程序运行的进程号,程序重新运行子进程重启在启动一个。

(2)进程的基本用法

例:

  1. import os
  2. from multiprocessing import Process
  3. def func():
  4. print("1.子进程id>>>%s,父进程id>>>%s" %(os.getpid(),os.getppid()))
  5.  
  6. if __name__ == "__main__":
  7. print("2.子进程id>>>%s,父进程id>>>%s" % (os.getpid(), os.getppid()))
  8. #创建子进程,返回一个进程对象.target是指定要完成的任务,后面接的是函数
  9. p = Process(target = func)
  10. # 调用子进程
  11. p.start()

结果是:函数外的父进程号是不变的,子进程号和函数内的父进程号是相同的,而且每次运行进程号是在改变的,函数内的子进程号每次也是改变的。

(3)函数中带有参数
进程的并发要依靠cpu
cpu先执行谁后执行谁,要依靠cpu调度策略
# 无参函数

#例:

  1. from multiprocessing import Process
  2. import os
  3.  
  4. def func():
  5. for i in range(1,6):
  6. print("2.子进程id>>>%s,父进程id>>>%s" %(os.getpid(),os.getppid()))
  7. if __name__ == "__main__":
  8. print("1.子进程id>>>%s,父进程id>>>%s" % (os.getpid(),os.getppid()))
  9. # 创建子进程
  10. p = Process(target=func)
  11. # 调用子进程
  12. p.start()
  13.  
  14. n = 5
  15. for i in range(1,n+1):
  16. print("*" * i)

#先打印星星后打印func函数内的循环,因为创建子进程中需要开辟栈帧空间需要时间

效果截图:

# 有参函数

  1. from multiprocessing import Process
  2. import os,time
  3. def func(n):
  4. for i in range(1,n+1):
  5. time.sleep(0.5)
  6. print("2.子进程id>>>%s,父进程id>>>%s" % (os.getpid(), os.getppid()))
  7. if __name__ == "__main__":
  8. print("1.子进程id>>>%s,父进程id>>>%s" % (os.getpid(), os.getppid()))
  9. n = 5
  10. # 创建子进程 返回进程对象 如果有参数用args 关键字参数执行
  11. # 对应的值是元组,参数塞到元组中,按照次序排列
  12. p = Process(target=func,args=(n,))
  13. p.start()
  14.  
  15. for i in range(1,n+1):
  16. time.sleep(0.3)
  17. print("*" * i)

# 这时候会造成,星星和func里面打印子进程和父进程的语句相互交错
# 因为子进程开辟栈帧空间的时间极短,所有再哪个不在睡眠时间内先运行哪个进程

效果截图:

(4)进程之间的数据彼此是隔离的

#例:

  1. from multiprocessing import Process
  2. count = 99
  3. def func():
  4. global count
  5. count +=1
  6. print("我是子进程,count=",count)
  7.  
  8. if __name__ == "__main__":
  9. p = Process(target=func)
  10. p.start()
  11. print("我是主进程,count=",count)

结果输出为:
我是主进程,count= 99
我是子进程,count= 100

(5)多个进程的并发

#例:

  1. # 在程序并发时, 因为cpu的调度策略问题,不一定谁先执行,谁后执行
  2. from multiprocessing import Process
  3. import os
  4. def func(args):
  5. print("args=%s,子进程id号>>>%s, 父进程id号>>>%s" % (args, os.getpid(), os.getppid()))
  6.  
  7. if __name__ == "__main__":
  8. for i in range(10):
  9. Process(target=func, args=(i,)).start()

运行得到结果如下图:

可以看出父进程id号是不变的,子进程id号是变化的,而且子进程开启不是按顺序的是并发的。

(6)子进程和父进程之间的关系
通常情况下,父进程会比子进程速度稍快,但是不绝对
在父进程执行所有代码完毕之后,会默认等待所有子进程执行完毕
然后在彻底的终止程序,为了方便进程的管理
如果不等待,子进程会变成僵尸进程,在后台不停地占用内存和cpu资源
但是本身由于进程太多,并不容易发现
#例:

  1. from multiprocessing import Process
  2. import os,time
  3. def func(args):
  4. print("args=%s,子进程id号>>>%s,父进程id号>>>%s" % (args, os.getpid(), os.getppid()))
  5. time.sleep(1)
  6. print("args= %s, end" % (args))
  7.  
  8. if __name__ == "__main__":
  9. for i in range(10):
  10. Process(target=func,args=(i,)).start()
  11. """
  12. Process(target=func,args=(i,)).start()
  13. Process(target=func,args=(i,)).start()
  14. Process(target=func,args=(i,)).start()
  15. Process(target=func,args=(i,)).start()
  16. Process(target=func,args=(i,)).start()
  17. Process(target=func,args=(i,)).start()
  18. ....
  19. """
  20. print("*******父进程*******")

运行后的结果为:

可以看出父进程号是不变的,子进程是并发的,父进程的执行语句是最快结束的,因为开启子进程需要时间,而主进程的输出没有阻塞所以最快,从print("args= %s, end" % (args))可以知道,子进程是并发的,因为sleep(1)后,如果是顺序执行的话,输出结果不是这样。

四:同步 异步 / 阻塞 非阻塞

场景在多任务当中

同步:必须等我这件事干完了,你在干,只有一条主线,就是同步

异步:没等我这件事情干完,你就在干了,有两条主线,就是异步

阻塞:比如代码有了input,就是阻塞,必须要输入一个字符串,否则代码不往下执行

非阻塞:没有任何等待,正常代码往下执行.

 

# 同步阻塞  :效率低,cpu利用不充分

# 异步阻塞  :比如socketserver,可以同时连接多个,但是彼此都有recv

# 同步非阻塞:没有类似input的代码,从上到下执行.默认的正常情况代码

# 异步非阻塞:效率是最高的,cpu过度充分,过度发热

 

1join阻塞基本用法

#例:

  1. from multiprocessing import Process
  2. def func():
  3. print("我发送第一封邮件....")
  4.  
  5. if __name__ == "__main__":
  6. p = Process(target=func)
  7. p.start()
  8. # 等待p对象的这个子进程执行完毕之后,在向下执行代码
  9. # join实际上是加了阻塞
  10. p.join() #如果没有join,往往主进程先运行,因为子进程需要开辟栈帧空间相当于加了阻塞
  11. print("发送第十封邮件")

输出结果为:

我发送第一封邮件....

发送第十封邮件

#程序在发送第十封邮件前加了阻塞,是的会先运行子进程结束在运行join之后的语句

(2) 多个子进程通过join 加阻塞,进行同步的控制

例:

  1. from multiprocessing import Process
  2. import time
  3. def func(index):
  4. time.sleep(0.3)
  5. print("第%s封邮件已经发送..." % (index))
  6.  
  7. if __name__ == "__main__":
  8. lst = []
  9. for i in range(1,10):
  10. p = Process(target=func,args=(i,))
  11. p.start()
  12. lst.append(p)
  13.  
  14. # 把列表里面的每一个进程对象去执行join()
  15. # 必须等我子进程执行完毕之后了,再向下执行,控制父子进程的同步性
  16. for i in lst:
  17. i.join()
  18. # 等前9个邮件发送之后了,再发第十个
  19. print("发送第十封邮件")

所以输出结果为:

第3封邮件已经发送...

第2封邮件已经发送...

第1封邮件已经发送...

第5封邮件已经发送...

第9封邮件已经发送...

第6封邮件已经发送...

第4封邮件已经发送...

第7封邮件已经发送...

第8封邮件已经发送...

发送第十封邮件

十个子进程是并发的,所以不一定谁先执行结束,所以不是顺序的。

(3)使用类的方法创建子进程

# (1) 基本语法
可以使用自定义的方式创建子进程,
但是必须继承父类Processs
而且所有的逻辑都必须写在run方法里面
#例:

  1. from multiprocessing import Process
  2. import os
  3. class MyProcess(Process):
  4. # 必须使用叫做run的方法,而且()里面只能是self
  5. def run(self):
  6. # 写自定义的逻辑
  7. print("子进程id>>>%s, 父进程的id>>>%s" % (os.getpid(), os.getppid()))
  8.  
  9. if __name__ == "__main__":
  10. p = MyProcess()
  11. p.start()
  12. print("主进程:{}".format(os.getpid()))

输出结果为:

主进程:8236

子进程id>>>6412, 父进程的id>>>8236

# (2) 带参数的子进程函数
#例:

  1. from multiprocessing import Process
  2. import os
  3. class MyProcess(Process):
  4.  
  5. def __init__(self,arg):
  6. # 必须调用一下父类的初始化构造方法
  7. super().__init__()
  8. self.arg = arg
  9.  
  10. # 必须使用叫做run的方法
  11. def run(self):
  12. # 在这里就得获取参数
  13. print("子进程id>>>%s,父进程的id>>>%s" % (os.getpid(),os.getppid()))
  14. print(self.arg)
  15.  
  16. if __name__ == "__main__":
  17. lst = []
  18. for i in range(1,10):
  19. p = MyProcess("参数:%s" % (i))
  20. p.start()
  21. lst.append(p)
  22.  
  23. for i in lst:
  24. i.join()
  25.  
  26. print("最后执行主进程的这句话...",os.getpid())

运行结果为:

子进程id>>>5964,父进程的id>>>5336

参数:2

子进程id>>>10544,父进程的id>>>5336

参数:3

子进程id>>>11512,父进程的id>>>5336

参数:4

子进程id>>>11160,父进程的id>>>5336

参数:5

子进程id>>>12068,父进程的id>>>5336

参数:1

子进程id>>>5288,父进程的id>>>5336

参数:6

子进程id>>>11380,父进程的id>>>5336

参数:8

子进程id>>>8092,父进程的id>>>5336

参数:7

子进程id>>>7120,父进程的id>>>5336

参数:9

最后执行主进程的这句话... 5336

结果分析:父进程是程序运行的主进程号不变,子进程是并发的所以那个参数先打印是不固定的,然后对每个子进程添加了join阻塞,所以没有全部执行完子进程之前,主进程的运行语句是不打印的,也就是在子进程join后主进程运行语句必须等待子进程全部结束才打印。

Python 之并发编程之进程上(基本概念、并行并发、cpu调度、阻塞 )的更多相关文章

  1. python并发编程之进程、线程、协程的调度原理(六)

    进程.线程和协程的调度和运行原理总结. 系列文章 python并发编程之threading线程(一) python并发编程之multiprocessing进程(二) python并发编程之asynci ...

  2. Java并发编程原理与实战二:并行&并发&多线程的理解

    1.CPU的发展趋势: 核心数目依旧会越来越多,根据摩尔定律,由于单个核心性能提升有着严重的瓶颈问题,普通的PC桌面在2018年可能回到24核心. 2.并发和并行的区别: 所有的并发处理都有排队等候, ...

  3. python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)

    9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型 池子内什么时候装线程:并发的任务属于I ...

  4. 15.python并发编程(线程--进程--协程)

    一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...

  5. Java并发编程:进程的创建

    Java并发编程:进程的创建 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...

  6. 原创】Java并发编程系列2:线程概念与基础操作

    [原创]Java并发编程系列2:线程概念与基础操作 伟大的理想只有经过忘我的斗争和牺牲才能胜利实现. 本篇为[Dali王的技术博客]Java并发编程系列第二篇,讲讲有关线程的那些事儿.主要内容是如下这 ...

  7. [书籍翻译] 《JavaScript并发编程》第六章 实用的并发

    本文是我翻译<JavaScript Concurrency>书籍的第六章 实用的并发,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript ...

  8. Python之路(第三十七篇)并发编程:进程、multiprocess模块、创建进程方式、join()、守护进程

    一.在python程序中的进程操作 之前已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起来的python程序 ...

  9. python并发编程之进程池,线程池,协程

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

随机推荐

  1. [Linux kali] linux kali [KDE]一些软件切换输入法无效

    #开始 今天最终是在实体机安装了Kali Kali的默认桌面是GNOME桌面 但是用久了windows桌面用这个实在是不习惯 然后看到了kali有自带KDE版本的 然后就下载了一个尝尝鲜 之前在Deb ...

  2. 【PAT甲级】1087 All Roads Lead to Rome (30 分)(dijkstra+dfs或dijkstra+记录路径)

    题意: 输入两个正整数N和K(2<=N<=200),代表城市的数量和道路的数量.接着输入起点城市的名称(所有城市的名字均用三个大写字母表示),接着输入N-1行每行包括一个城市的名字和到达该 ...

  3. 【C语言】计算N名同学的某门功课的平均成绩

    分析: 循环输入number只童鞋的成绩,累加为sum,最后输出sum/number即可! 代码: #include<stdio.h> int main() { , score;//sco ...

  4. 【MySQL】完整性约束

    " 目录 not null default unique 单列唯一 联合唯一 primary key 单列主键 复合主键 auto_increment 步长与偏移量 foreign key ...

  5. Java读文件夹

    使用JAVA读取文件夹中的多个文件 package hx.ReadFile; import java.io.FileNotFoundException; import java.io.IOExcept ...

  6. 【工具类】Java中判断字符串是否为数字的五种方法

    1 //方法一:用JAVA自带的函数 2 public static boolean isNumeric(String str){ 3 for (int i = str.length();--i> ...

  7. 例题3_1 TeX中的引号(TeX Quotes,UVa 272)

    在TeX中,左双引号是“``”,右双引号是“''”.输入一篇包含双引号的文章,你的任务是把它转换成TeX的格式. 样例输入: "To be or not to be,"quoth ...

  8. USER 指定当前用户,希望以某个已经建立好的用户来运行某个服务进程,不要使用 su 或者 sudo,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 gosu

    USER 指定当前用户 格式:USER <用户名>[:<用户组>] USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层.WORKDIR 是改变工作目录,US ...

  9. 吴裕雄--天生自然TensorFlow2教程:激活函数及其梯度

    import tensorflow as tf a = tf.linspace(-10., 10., 10) a with tf.GradientTape() as tape: tape.watch( ...

  10. JS vue 组件创建过程

    https://www.jianshu.com/p/3504a1edba42 vue.js原生组件化开发(一)——组件开发基础 0.3472017.05.09 12:00:54字数 1120阅读 33 ...