多任务原理

什么叫多任务? ? ?

  • 现代操作系统(Windows. Mac OS、Linux、 UNIX等)都支持多任务
  • 操作系统同时可以运行多个任务
单核CPU实现多任务原理

操作系统轮流让各个任务交替执行,QQ执行2us,切换到微信,在执行2us, 再切换到陌陌,执行.2…表面是看,每个任务反复执行下去
但是CPU调度执行速度太快了,导致我们感觉就像所有任务都在同时执行一样

多核CPU实现多任务原理

真正的并性执行多任务,只能在多核CPU上实现,但是由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行

  • 并发:看上去一起执行,任务书数多于CPU核心数
  • 并行:真正起执行,任务数小于等于CPU核心数

实现多任务的方式:

  1. 多进程模式
  2. 多线程模式
  3. 协程模式
  4. 多进程+多线程模式

进程

对于操作系统而言,一个任务就是一个进程。

进程是系统中程序执行和资源分配的基本单位,每个进程都有属于自己的数据段、代码段、堆栈段,互不干扰,互不影响

单任务现象

import timedef run():while True:print("aaa")time.sleep(1.2)if __name__ == "__main__":while True:print("jack")time.sleep(1)# 永远也不会执行到run方法,只有上面的while循环结束才可以执行。# 这是单任务现象。run()

运行结果:

永远也执行不到上面的run方法中的aaa,这就是单线程,只能等一个执行完了再执行另一个

启动进程实现多任务

import os
from multiprocessing import Process
import time# 子进程需要执行的代码
def run(value):while True:# os.getpid()获取当前进程的id号# os.getppid()获取当前进程的父进程的id号print("aaa----%s----%s----%s" % (value, os.getpid(), os.getppid()))time.sleep(1.2)if __name__ == "__main__":print("主(父)进程启动 %s" % (os.getpid()))# 创建子进程# target说明进程执行的任务# args可以传参,因为是元组,所以只传一个参数要加逗号p = Process(target=run, args=("ok",))# 启动进程p.start()while True:print("jack")time.sleep(1)

运行结果:

可以很明显的看到,两个是同时进行的,因为停顿的秒数不同,但确确实实是两个while True在运行,很神奇,另外(target=run),方法是需要加括号的,只需要传入方法名就行

父进程和子进程的先后顺序

from multiprocessing import Process
import timedef run():print("子进程开始")time.sleep(2)print("子进程结束")def eat():print("开始吃")time.sleep(1)print("吃完了")if __name__ == "__main__":print("父进程开始")p = Process(target=run)p.start()p1 = Process(target=eat)p1.start()# 可以发现,父进程根本也没有等子进程执行完在结束,而是各执行各的time.sleep(1)print("父进程结束")

运行结果:

可以发现,父进程根本也没有等子进程执行完在结束,而是各执行各的,但是这并不符合常规
正常的应该是老板父进程)指挥员工子进程)做事

让父进程等待子进程执行完之后再结束
from multiprocessing import Process
import timedef run():print("子进程开始")time.sleep(2)print("子进程结束")def eat():print("开始吃")time.sleep(1)print("吃完了")if __name__ == "__main__":print("父进程开始")p = Process(target=run)p.start()p1 = Process(target=eat)p1.start()# 要想让父进程等待子进程执行完在结束,在下面加个.join()p.join()p1.join()time.sleep(1)print("父进程结束")

运行结果:

启动大量子进程

查看电脑核心数的方法
1、打开任务管理器

2、点击性能

3、查看核心数,上面显示的是6核心12个逻辑处理器,说明我们可以同时进行12个任务

例子:

import os
import random
import time
from multiprocessing import Pooldef run(name):print("子进程%d启动--%s" % (name, os.getpid()))start = time.time()time.sleep(random.choice([1, 2, 3]))end = time.time()print("子进程%d结束--%s--耗时%.2f" % (name, os.getpid(), end - start))if __name__ == "__main__":print("父进程启动")# 创建多个进程# 进程池# Pool(n)  n表示可以同时执行的进程数量,不写的话,默认大小为CPU核心数pool = Pool(4)for i in range(1, 6):# 创建进程,放入进程池统一管理pool.apply_async(run, args=(i,))# 在调用join之前必须先调用close,调用close之后就不能再继续添加新的进程了pool.close()pool.join()print("父进程结束")

运行结果:

请看仔细一点,在进程2结束的瞬间,进程5启动,而且他们用的是同一个进程号,是这个进程工作完立马去工作下一个!
笔者因为偷懒,所以用循环处理一种方法,如果要进行不同的进程
例子:

# 我们可以这样
if __name__ == "__main__":print("父进程启动")# 因为要执行的进程大于我们池子的容量,才看得出效果pool = Pool(2)# 定义不同的进程pool.apply_async(run1)pool.apply_async(run2)pool.apply_async(run3)pool.close()pool.join()print("父进程结束")

因为笔者比较偷懒,故没有作演示,请见谅

全局变量在多个进程中不能共享

from multiprocessing import Process
import timenum = 100def run():print("子进程开始")# 若想在函数内部对函数外的变量进行操作,就需要在函数内部声明其为globalglobal numnum += 1time.sleep(2)print("子进程结束")def eat():print("开始吃")time.sleep(3)print("吃完了")if __name__ == "__main__":print("父进程开始")print(num)p = Process(target=run)p.start()p.join()# 在子进程中修改全局变量对父进程中的全局变了没有影响# 在创建子进程时对全局变量做了一个备份,父进程中的与子进程中的num是两个完全不同的两个变量# 两个子进程中也不能共享print("父进程结束")

运行结果:

可以看到,num数并没有改变,所以每个子进程都是单独工作的,全局变量在多个进程中不能共享

单进程拷贝文件

文件是15个空白的文本文档

import os
import timedef copy(readPath, writePath):# 读取两个文件fr = open(readPath, "rb")fw = open(writePath, "wb")# 读并写入context = fr.read()fw.write(context)# 关闭fr.close()fw.close()path = r"D:\新建文件夹\copy"
topath = r"D:\新建文件夹\tocopy"# 读取path下的所有的文件
fileList = os.listdir(path)# 启动for循环处理每一个文件
start = time.time()
for fileName in fileList:copy(os.path.join(path, fileName), os.path.join(topath, fileName))
end = time.time()
print("总耗时:%.5f" % (end - start))

运行结果:

总耗时:0.00400

多进程拷贝文件

import os
import time
from multiprocessing import Pooldef copy(readPath, writePath):# 读取两个文件fr = open(readPath, "rb")fw = open(writePath, "wb")# 读并写入context = fr.read()fw.write(context)# 关闭fr.close()fw.close()path = r"D:\新建文件夹\copy"
topath = r"D:\新建文件夹\tocopy"if __name__ == "__main__":# 读取path下的所有的文件fileList = os.listdir(path)start = time.time()pool = Pool(6)for fileName in fileList:pool.apply_async(copy, args=(os.path.join(path, fileName), os.path.join(topath, fileName)))pool.close()pool.join()end = time.time()print("总耗时:%.5f" % (end - start))

运行结果:

总耗时:0.19804

对比一下,是不是很惊讶,为什么多进程比单进程慢呢?

  • 极少的数据,多进程会比单进程,只有的数据才能体现出优势
  • 但是要是100个进程一起工作,理论上也不会快很多,因为因为多进程启动也费时间和资源,销毁也费时间与资源

我们现在测试一下2G,27个资源

  • 单进程:总耗时:19.93352
  • 多进程:总耗时:15.03159

总而言之,多进程理论上是比单进程快些

封装进程对象

我们先创建进程类
名字叫jackProcess.py

import time
from multiprocessing import Process
import os# 继承自Process
class JackProcess(Process):def __init__(self, name):Process.__init__(self)self.name = namedef run(self):print("子进程(%s--%s)启动" % (self.name, os.getpid()))time.sleep(2)print("子进程(%s--%s)结束" % (self.name, os.getpid()))

然后再把类实例化
创建一个新文件

from jackProcess import JackProcessif __name__ == "__main__":print("父进程启动")# 创建子进程pool = JackProcess("test")# 自动调用pool进程对象的run方法pool.start()pool.join()print("父进程结束")

运行结果:

不知道大家有没有注意,我们这里并没有调用run方法,然后也可以执行,这是为什么呢?
因为我们使用pool.start的时候,它会自动调用类里面的方法,很方便,如果有100个方法需要我们去调用,那把进程封装进对象,这样无疑是最方便最快速的

进程间通信

进程中的子进程是不能共享数据的,但是能互相拿数据和给数据
multiprocessing中的Queue
相当于把子进程A的东西传到队列中去,然后子进程B再从队列中拿数据

from multiprocessing import Process, Queue
import os
import timedef write(queue):print("启动写子进程--%s" % (os.getpid()))for i in range(1,5):# 把数据给队列queue.put(i)time.sleep(1)print("结束写子进程--%s" % (os.getpid()))def read(queue):print("启动读子进程--%s" % (os.getpid()))while True:# 从队列里面拿数据,True是一直拿value = queue.get(True)print("value = " + str(value))print("结束读子进程--%s" % (os.getpid()))if __name__ == "__main__":print("父进程开始")# 父进程创建队列,并传递给子进程q = Queue()pw = Process(target=write, args=(q,))pr = Process(target=read, args=(q,))# 虽然这两个先是pw在前,但是不一定执行的时候是pw在前pw.start()pr.start()pw.join()print("父进程结束")

为什么拿要用死循环呢?因为read方法如果从队列里面拿的话,根本不知道什么时候拿,拿什么,所以我们要一直拿
运行结果:

有发现,我们的程序一直都在运行,这是为什么呢?因为我们的read方法是死循环,根本结束不了,所以我们要强制性结束

 pw.join()# pr进程里面是个死循环,无法等待其结束,只能强行结束pr.terminate()print("父进程结束")

运行结果:

如果有错误或者有疑问,请私信我喔,感谢观看

Python中进程与线程的(详细)教程之进程相关推荐

  1. Python中的log文件(详细教程)

    1.写在前面 2.代码1:在控制台输出log日志 3.代码2:在文件中写入log日志 4. 代码3:在控制台和文件中分别输出log日志 写在前面 log日志一般使用是很方便的,一般使用第二种即可. 详 ...

  2. python -- PyQt5(designer)中文详细教程(一)Qt的基本功能

    在介绍PyQt5中文详细教程前,如有需要安装PyQt5的同学可以在此 PyQt5安装详细教程_M_Q_T的博客-CSDN博客参考安装,里面有详细的安装内容. 下一章内容python -- PyQt5( ...

  3. class括号里的object_听说你在找python中class的定义及使用教程?看这里就对了

    这篇文章主要介绍了python中class的定义及使用,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下. 类的定义 class classname[(父类名)]: ...

  4. Python实现照片大小调整的详细教程

    Python实现照片大小调整的详细教程 照片大小调整在图片处理过程中是必不可少的一个环节,本文将详细介绍如何使用Python实现对照片大小的调整,以及相应的代码实现. 环境准备 在开始编写代码之前,需 ...

  5. 进程、线程、协程 关于进程、线程、协程,有非常详细和丰富的博客或者学习资源,我不在此做赘述,我大致在此介绍一下这几个东西。 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。

    进程.线程.协程 关于进程.线程.协程,有非常详细和丰富的博客或者学习资源,我不在此做赘述,我大致在此介绍一下这几个东西. 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程 ...

  6. amazon海淘+CUL中美速递转运详细教程(免税)

    amazon海淘+CUL中美速递转运详细教程(免税) 9月15日开始amazon和drugstore(我常用的两家)征收消费税,运到免税州,要收取费用中转到加州再发货.偶然发现CUL中美速递有免税州直 ...

  7. python中GIL和线程与进程

    线程与全局解释器锁(GIL) 一.线程概论 1.何为线程 每个进程有一个地址空间,而且默认就有一个控制线程.如果把一个进程比喻为一个车间的工作过程那么线程就是车间里的一个一个流水线. 进程只是用来把资 ...

  8. python线程暂停_在python中暂停一个线程和另一个线程

    我正在研究如何在python中执行多线程(2个线程).在 我要他们中的一个一直在读串行端口.读取每个帧并将其保存到数据库中.我已经做了一个脚本来做这个.在 对于第二个,我希望它监听一个套接字端口.当它 ...

  9. 一文搞定Linux进程和线程(详细图解)

    Linux 进程和线程 本篇文章我们就深入理解一下 Linux 内核来理解 Linux 的基本概念之进程和线程.系统调用是操作系统本身的接口,它对于创建进程和线程,内存分配,共享文件和 I/O 来说都 ...

最新文章

  1. PLSQL developer 连接不上64位Oracle 解决办法
  2. 英伟达“暴力碾压”谷歌:53分钟训练完BERT,2.2毫秒完成推理,创下NLP三项新纪录...
  3. MATLAB从入门到精通-最速下降算法、牛顿算法、BFGS拟牛顿算法、共轭梯度算法无约束极值问题
  4. 【简单数论】H - A^X mod P_HRBUST - 2049_31行代码AC
  5. AIX-vi操作-提示Unknown terminal type的问题解决方法
  6. Mysql中代替like模糊查询的一种方法
  7. L1-031 到底是不是太胖了 (10 分)—团体程序设计天梯赛
  8. 【JavaScript】使用DOM修改和查询CSS内联样式
  9. android根目录无权访问,关于android:已注册为Git根目录,但未在其中找到任何Git存储库...
  10. 华为鸿蒙麒麟玉兔_华为!《鸿蒙出世:中国神兽图鉴》
  11. 一个一年工作经验的菜鸡程序员的一年总结
  12. OpenGLGLUT入门学习
  13. 01、iphone越狱恢复,去越狱,手机归零
  14. 【i春秋 CTF Crypto】2015广州强网杯致敬经典
  15. MATLAB: 2018a百度云资源、迅雷资源、安装步骤
  16. 广州电信新推出的实惠套餐(目前更新时间3月27日,非官方口径,不正确的地方请指出)...
  17. java工具类怎么写_常用的Java工具类——十六种
  18. 【低代码开发】智慧水务解决方案
  19. 【Eclipse的正确打开方式】从Libraries中的jar包到源代码和API连接
  20. 精编,精讲,精练,精益求精---AP微积分第10版在精雕细琢反复打磨中与你相遇

热门文章

  1. 《机器学习》实验一:线性回归
  2. props写法_Vue中props的用法知识点
  3. 苹果手机查找显示无法连接服务器是怎么回事,iphone手机无法连接服务器怎么办?贝锐网站建站有哪些特点?...
  4. 从MySQL到MongoDB
  5. 判断点在直线的一哪侧
  6. ActiveMQ开发与简介
  7. chmod 命令参数
  8. JAVA Springboot学习
  9. COMSOL中接触面积计算
  10. 性能堪比iPhone4 苹果iPod touch4对比评测