一: 进程的概念:(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()  获取父进程号

#例:

import os, time

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

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

(2)进程的基本用法

例:

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

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

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

#例:

from multiprocessing import Process
import os def func():
for i in range(1,6):
print("2.子进程id>>>%s,父进程id>>>%s" %(os.getpid(),os.getppid()))
if __name__ == "__main__":
print("1.子进程id>>>%s,父进程id>>>%s" % (os.getpid(),os.getppid()))
# 创建子进程
p = Process(target=func)
# 调用子进程
p.start() n = 5
for i in range(1,n+1):
print("*" * i)

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

效果截图:

# 有参函数

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

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

效果截图:

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

#例:

from multiprocessing import Process
count = 99
def func():
global count
count +=1
print("我是子进程,count=",count) if __name__ == "__main__":
p = Process(target=func)
p.start()
print("我是主进程,count=",count)

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

(5)多个进程的并发

#例:

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

运行得到结果如下图:

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

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

from multiprocessing import Process
import os,time
def func(args):
print("args=%s,子进程id号>>>%s,父进程id号>>>%s" % (args, os.getpid(), os.getppid()))
time.sleep(1)
print("args= %s, end" % (args)) if __name__ == "__main__":
for i in range(10):
Process(target=func,args=(i,)).start()
"""
Process(target=func,args=(i,)).start()
Process(target=func,args=(i,)).start()
Process(target=func,args=(i,)).start()
Process(target=func,args=(i,)).start()
Process(target=func,args=(i,)).start()
Process(target=func,args=(i,)).start()
....
"""
print("*******父进程*******")

运行后的结果为:

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

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

场景在多任务当中

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

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

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

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

 

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

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

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

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

 

1join阻塞基本用法

#例:

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

输出结果为:

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

发送第十封邮件

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

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

例:

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

所以输出结果为:

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

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

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

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

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

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

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

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

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

发送第十封邮件

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

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

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

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

输出结果为:

主进程:8236

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

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

from multiprocessing import Process
import os
class MyProcess(Process): def __init__(self,arg):
# 必须调用一下父类的初始化构造方法
super().__init__()
self.arg = arg # 必须使用叫做run的方法
def run(self):
# 在这里就得获取参数
print("子进程id>>>%s,父进程的id>>>%s" % (os.getpid(),os.getppid()))
print(self.arg) if __name__ == "__main__":
lst = []
for i in range(1,10):
p = MyProcess("参数:%s" % (i))
p.start()
lst.append(p) for i in lst:
i.join() 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. 「CSP-S模拟赛」2019第一场

    目录 T1 小奇取石子 题目 考场思路 正解 T2 「CCO 2017」专业网络 题目 考场思路 题解 T3 「ZJOI2017」线段树 题目 考场思路 正解 这场考试感觉很奇怪. \(T1.T2\) ...

  2. 4、maven——构建生命周期

    什么是生命周期? 构建生命周期是一组阶段的序列(sequence of phase),每个阶段定义了目标被执行的顺序,这里的阶段就是生命周期的一部分. 一个典型的Maven生命周期由一些几个阶段的序列 ...

  3. 【代码学习】PYTHON 私有化

    一.私有化 xx: 公有变量_x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问__xx:双前置下划线,避免与子类中的属性命名冲突,无 ...

  4. 页面布局 Wrap 组件 和 RaisedButton按钮

    一.RaisedButton 定义一个按钮 Flutter 中通过 RaisedButton 定义一个按钮.RaisedButton 里面有很多的参数,只讲简单的进行使用. return Raised ...

  5. Educational Codeforces Round 81 (Rated for Div. 2) - D. Same GCDs(数学)

    题目链接:Same GCDs 题意:给你两个数$a$,$m(1 \leq a < m \leq 10^{10})$,求有多少个$x$满足:$0 \leq x < m$且$gcd(a,m)= ...

  6. 【PAT甲级】1096 Consecutive Factors (20 分)

    题意: 输入一个int范围内的正整数,输出它最多可以被分解为多少个连续的因子并输出这些因子以*连接. trick: 测试点5包含N本身是一个素数的数据,此时应当输出1并把N输出. 测试点5包含一个2e ...

  7. Kosaraju's algorithm

    推荐到我的这篇博客中看完整版的. 该算法用于求解有向图的强连通分量,也就是强连通子图的个数. 算法实现摘自Kosaraju's algorithm - 百度百科: #include <iostr ...

  8. 2.2.FastDFS-单机拆分版-存储器安装配置

    Centos610系列配置 我们在Centos610FastDFS单机模式-FastDFS安装 中已经完成了FastDFS的安装,接下来我们进行FastDFS存储器的安装. 1.找到FastDFS配置 ...

  9. 序列变换 HDU - 5256

    序列变换 HDU - 5256 题目链接 题目 我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数. 请输出最少需 ...

  10. springmvc中整合mongodb副本集配置文件

    配置文件jdbc.properties: mongo.hostport=192.168.100.100:28007,192.168.100.110:28008,192.168.100.120:2800 ...