34 并发编程1 进程

并发编程

1 回顾

计算机五大组成部分
控制器 运算器 存储器 输入设备 输出设备
CPU = 控制器 + 运算器

程序的运行过程,先将程序代码从硬盘移动到内存中,CPU再从内存中读取代码并执行。

2 多道技术

目标:让单核实现并发的效果。

2.1 并发 与 并行

在这里插入图片描述
并发 (concurrent) 是指多个任务轮流交替使用资源,表面上看起来具有同时处理多个任务的能力,在一段时间中看上去是在同时执行多个任务;
并行 (parallel) 是指多任务同时执行,真正拥有在同一时刻处理多个任务的能力。

并行肯定是并发,是并发的子集。
单核处理器肯定不能实现并行,但可以实现并发。

2.2 多道技术

单道也称为串行,指的是一个任务完整地运行完毕后,才可以运行下一个任务。

多道,即多路复用,是一种任务调度机制,可以节省复数个程序同时运行时的总耗时,充分利用计算机系统的资源。
多道程序系统是在计算机内存中同时存放复数个相互独立的程序,它们在管理程序(操作系统)的控制下,以交替的方式共享争夺系统资源。

  1. 空间上的复用
    多个程序共同使用同一套计算机硬件(例如内存空间);
  2. 时间上的复用
    切换 + 保存状态
    多个程序同时共享系统资源,例如程序A占用CPU执行时,程序B可以占用IO设备进行数据输入输出操作,这样可以使系统中的各种资源尽可能地满负荷工作,从而提高整个计算机系统的使用效率。

多道技术的实现
单核CPU在任何时刻只能执行一个进程,目标是减少CPU的空闲时间。

CPU切换

  1. 当一个程序执行IO等操作时,操作系统会剥夺该程序对CPU的执行权;
    目的:提高了CPU的利用率,并且不影响程序的执行效率。
  2. 当一个程序长时间占用CPU时,操作系统会剥夺该程序对CPU的执行权;
    作用:使得多个程序交替运行来实现并发,但会降低了单个程序的执行效率。

3 进程

进程指的是计算机中正在执行的程序。

3.1 进程调度

进程是系统进行资源分配和调度的基本单位。
为了实现多个进程交替运行,操作系统必须对这些进程进行调度。

  1. 先来先服务(FCFS)调度算法
    有利于长作业,而不利于短作业;
  2. 短作业优先(SJ/PF)调度算法
    对长作业不利,不能保证紧迫性作业被及时处理;
  3. 时间片轮转法(Round Robin,RR)
    让每个进程在就绪队列中的等待时间与享受服务的时间成比例。
  4. 多级反馈队列
    设置多个就绪队列,并为各个队列赋予不同的优先级和不同的执行时间,各队列的任务优先级逐个降低,任务需要的执行时间片逐个增加;
    当一个新进程进入内存后,首先将它放入第一队列的末尾,当轮到该进程执行时,如它能在该队列的设置的时间内完成,便可准备撤离,否则将该进程移入下一个队列的末尾;
    只有当前队列空闲时,系统才调度执行下一个队列中的进程。

3.2 进程三状态图

在这里插入图片描述

  1. 就绪(Ready)状态
    当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行;
  2. 执行/运行(Running)状态
    当进程已获得处理机,正在处理机上执行;
  3. 阻塞(Blocked)状态
    正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件包括:等待I/O操作完成、等待信件(信号)等。

3.3 重要概念

  1. 同步与异步
    同步与异步描述的是任务的提交方式
    同步:任务提交后,等待返回结果,等待期间不做任何事情;
    异步:任务提交后,不会等待返回结果,直接去做其它事情,返回结果通过异步回调机制自动处理。
  2. 阻塞与非阻塞
    阻塞与非阻塞描述的是程序的运行状态
    阻塞:三状态图中的阻塞态;
    非阻塞:三状态图中的就绪态和运行态。

最高效的组合:异步 + 非阻塞
理想状态:程序始终处在就绪态和运行态之间切换。

4 开启进程

Windows系统中创建进程必须放入main的子代码块中
因为Windows下创建进程(进程对象.start())的过程类似于模块导入的过程,会以模块导入的方式从重新上往下依次执行代码,若创建进程的代码未放入main的子代码块中,则会导致无限死循环。
Linux中则是将代码完整地拷贝一份。

4.1 开启进程方式1
from multiprocessing import Process
import time


def task(name):
    print('{name} is running'.format(name=name))
    time.sleep(1)
    print('{name} is over'.format(name=name))


# windows系统中创建继承必须在main的子代码块中完成。
if __name__ == '__main__':
    # 1. 创建进程对象
    p = Process(target=task, args=('Task1',))
    # 2. 通知操作系统创建进程,异步
    # 通知时代码会继续往下执行,具体完成创建进程的时间不确定。
    p.start()
4.2 开启进程方式2

采用类的继承

from multiprocessing import Process
import time


class CustomProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print('{name} is running'.format(name=self.name))
        time.sleep(1)
        print('{name} is over'.format(name=self.name))


if __name__ == '__main__':
    p = CustomProcess('Task1')
    p.start()
4.3 总结

创建进程就是在内存中申请一片内存空间,将待执行的代码存入其中,
每一个进程对应一块独立的内存空间。
进程与进程之间默认无法之间传输数据,可以借助第三方工具实现。

4.4 join

join函数的作用是让主进程的代码等待子进程的代码执行结束后,再继续执行,不会影响其它子进程执行代码。

from multiprocessing import Process
import time


def task(name):
    print('{name} is running'.format(name=name))
    time.sleep(1)
    print('{name} is over'.format(name=name))


if __name__ == '__main__':
    p1 = Process(target=task, args=('Task1',))
    p1.start()
    p1.join()
4.5 对比

串行

from multiprocessing import Process
import time


def task(name, t):
    print('{name} is running'.format(name=name))
    time.sleep(t)
    print('{name} is over'.format(name=name))


if __name__ == '__main__':
    start_time = time.time()

    for i in range(1, 4):
        p = Process(target=task, args=(f'Task{i}', i))
        p.start()
        p.join()
    # 当第一次执行p.join()时,代码不会继续执行,
    # 等待子进程执行完毕后,再执行新一轮循环,创建下一个子进程(start())
    end_time = time.time()
    print(end_time - start_time)  # ~6.3

并行

from multiprocessing import Process
import time


def task(name, t):
    print('{name} is running'.format(name=name))
    time.sleep(t)
    print('{name} is over'.format(name=name))


if __name__ == '__main__':
    start_time = time.time()

    p_list= []
    for i in range(1, 4):
        p = Process(target=task, args=(f'Task{i}', i))
        p.start()
        p_list.append(p)

    for each_p in p_list:
        p.join()
    # join只会阻塞主进程,不会影响其它子进程
    # 第一次运行join()时,其它子进程已经开始创建(start())了。
    end_time = time.time()
    print(end_time - start_time)  # ~3.1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值