并发编程之进程
时间:2020-04-22
本文章向大家介绍并发编程之进程,主要包括并发编程之进程使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、什么是进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作
系统结构的基础
狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
注意:同一个程序执行两次,就会在操作系统中出现两个进程,所以我们可以同时运行一个软件,分别做不同的事情也不会混乱。
二、进程调度
要想多个进程交替运行,操作系统必须对这些进程进行调度,这个调度也不是随即进行的,而是需要遵循一定的法则,由此就有了进程的调度算法。
先来先服务(FCFS)调度算法:对长作业有利,对短作业无益 短作业(进程)优先调度算法(SJ/PF):对短作业有利,多长作业无益
时间片轮转法+多级反馈队列:
三、进程的并发与并行
无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是
cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务
并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
并行:同时运行,只有具备多个cpu才能实现并行
四、同步\异步and阻塞\非阻塞
在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。 (1)就绪(Ready)状态 当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。 (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。 (3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种
例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
同步和异步:
所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务
序列
。要么成功都成功,失败都失败,两个任务的状态可以保持一致。
所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,
只要自己完成了整个任务
就算完成了
。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以
它是不可靠的任务序列
。
阻塞与非阻塞:
阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞
与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的
# 同步/异步与阻塞/非阻塞
同步阻塞形式 效率最低。举例子来说,就是你专心排队办银行业务,什么别的事都不做。 异步阻塞形式 如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发(通知),也就是领了一张小纸条,假如在这段时间里他不能离开银行做其它的
事情,那么很显然,这个人被阻塞在了这个等待的操作上面;异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞
同步非阻塞形式
实际上是效率低下的。想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要
在这两种不同的行为之间来回的切换,效率可想而知是低下的。
异步非阻塞形式
效率更高,因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换。
比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下,那么他就没有被阻塞在这个等待的
操作上面,自然这个就是异步+非阻塞的方式了。
很多人会把同步和阻塞混淆,是因为很多时候同步操作会以阻塞的形式表现出来,同样的,很多人也会把异步和非阻塞混淆,因为异步操作一般都不会在真正的IO操作处被阻塞。
五、python创建进程的两种方式
multiprocess模块不是一个模块而是python中一个操作、管理进程的包。 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎
包含了和进程有关的所有子模块,我们用的是process模块。process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
参数介绍:
1 group参数未使用,值始终为None
2 target表示调用对象,即子进程要执行的任务
3 args表示调用对象的位置参数元组,args=(1,2,'python',)
4 kwargs表示调用对象的字典,kwargs={'name':'python','age':18}
5 name为子进程的名称
1 p.start():启动进程,并调用该子进程中的p.run() 2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 3 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁 4 p.is_alive():如果p仍然运行,返回True 5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置 2 p.name:进程的名称 3 p.pid:进程的pid 4 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可) 5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候 ,就不会递归运行了。
在一个python进程中开启子进程,start方法和并发效果:
方式一: from multiprocessing import Process import time def task(name): print('%s is running'%name) time.sleep(3) print('%s is over'%name) if __name__ == '__main__': # 1 创建一个对象 p = Process(target=task, args=('name',)) # 容器类型哪怕里面只有1个元素 建议要用逗号隔开 # 2 开启进程 p.start() # 告诉操作系统帮你创建一个进程 异步 print('主进程')
方式二:类的继承 from multiprocessing import Process import time class MyProcess(Process): def run(self): print('hello word') time.sleep(1) print('get out!') if __name__ == '__main__': p = MyProcess() p.start() print('主进程')
join方法:让主进程等待子进程代码运行结束之后,再继续运行。不影响其他子进程的执行
import time from multiprocessing import Process def f(name): print('hello', name) time.sleep(1) print('我是子进程') if __name__ == '__main__': p = Process(target=f, args=('aaa',)) p.start() p.join() print('我是父进程')
多个进程同时运行(注意,子进程的执行顺序不是根据启动顺序决定的)
import time from multiprocessing import Process def f(name): print('hello', name) time.sleep(1) if __name__ == '__main__': p_lst = [] for i in range(5): # 使用for循环 p = Process(target=f, args=('aaa',)) p.start() p_lst.append(p)
多进程同时运行的join方法:
import time from multiprocessing import Process def f(name): print('hello', name) time.sleep(1) if __name__ == '__main__': p_lst = [] for i in range(5): p = Process(target=f, args=('aaa',)) p.start() p_lst.append(p) [p.join() for p in p_lst] print('父进程在执行')
进程之间的数据隔离问题:
from multiprocessing import Process money = 100 def task(): global money # 局部修改全局 money = 666 print('子进程',money) if __name__ == '__main__': p = Process(target=task) p.start() p.join() print(money)
原文地址:https://www.cnblogs.com/qjk95/p/12753534.html
- ExtJs学习笔记(19)_复杂Form示例
- Linux快速入门01-基础概念
- SQL学习之Insert的特殊用法(插入检索出的数据,表之间的数据复制)
- 对php多态的理解
- JavaScript值延迟脚本和异步脚本
- JavaScript之arguments.callee
- JavaScript之面向对象学九(原型式继承和寄生式继承)
- ExtJs学习笔记(18)_ExtJs嵌入FCK示例
- Html与CSS快速入门01-基础概念
- 利用Fck的javascript-API创建fck编辑器
- ASPNET_WEBAPI快速学习02
- ExtJs学习笔记(17)_table布局
- Markdown快速入门
- JavaScript之apply()和call()的区别
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Flink 自定义触发器实现带超时时间的 CountWindow
- 聊聊Spring Boot Actuator
- [译]按功能(特性)分包
- Spring Boot Admin简介及实践
- Spring Boot Admin实现服务健康预警
- 除了FastJson,你也应该了解一下Jackson(二)
- 除了FastJson,你也应该了解一下Jackson(一)
- JavaScript性能优化总结
- Spring Boot2+Resilience4j实现容错之Bulkhead
- [译]高性能缓存库Caffeine介绍及实践
- 云原生时代高性能Java框架—Quarkus(一)
- 云原生时代高性能Java框架—Quarkus(二)
- 使用TypeScript积累自己的类库
- 在Egret项目中使用protobuf
- JavaScript原型与继承