当前位置: 首页 > news >正文

进程、线程、协程

在这里插入图片描述

文章目录

  • 前言
  • 一、易混概念
    • 1.1 同步vs异步
    • 1.2 并发vs并行
  • 二、进程(Process)
    • 2.1进程概念
    • 2.2 进程三个基本状态
    • 2.3多进程方式编程
  • 三、线程(Thread)
    • 3.1 线程的引入
    • 3.2 线程概念
    • 3.3 多线程编程
    • 3.4 GIL对多线程的影响
    • 3.5 GIL是否意味着线程安全
  • 四、协程(Coroutine)
    • 4.1 协程概念
  • 总结

前言

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。

首先这三者是有明显的大小关系
进程 > 线程 > 协程
一个进程可以有多个线程,一个线程里面可以有多个协程


一、易混概念

1.1 同步vs异步

同步(sync):发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。 简
单来说,同步就是必须一件一件事做,等前一件做完了才能做下一件事。
异步( async):当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操
作。
在这里插入图片描述
同步和异步的区别:请求发出后,是否需要等待结果,才能继续执行其他操作。

1.2 并发vs并行

并发(Concurrency):指在行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。
在这里插入图片描述

并行(Parallelism):有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。
在这里插入图片描述

二、进程(Process)

2.1进程概念

一台计算机所能利用的资源总是有限的,比如 CPU 在 1 秒钟之内最多执行 1 亿条指令,计算机一共有6GB 的内存空间等等。因此,“如何提高计算机资源的利用率”是人们一直思考的问题,这个问题也一直带动着计算机硬件和软件的发展。

计算机发展早期,程序的控制历经:管理员>批处理>多任务操作系统

为了使多任务操作系统更高效地完成计算机资源的分配和回收,便于管理各个程序的执行过程,人们提出了“进程”的概念。

  • 进程是一个实体,结构包含程序、数据和进程控制块。
  • 每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。
    • 文本区域存储处理器执行的代码;
    • 数据区域存储变量和进程执行期间使用的动态分配的内存;
    • 堆栈区域存储着活动过程调用的指令和本地变量
  • 进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。

2.2 进程三个基本状态

进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程可能具有以下三种基本状态。

1)就绪状态(Ready):
    进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。

2)运行状态(Running):执行状态
    进程占用处理器资源;处于此状态的进程的数目小于等于处理器的数目。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。

3)阻塞状态(Blocked):
    由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理器资源分配给该进程,也无法运行。
在这里插入图片描述
(1) 就绪→运行态
处于就绪状态的进程,当进程调度程序为之分配了CPU后,该进程便由就绪状态转变成执行状态。

(2) 运行→就绪
处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出CPU,于是进
程从执行状态转变成就绪状态。

(3) 运行→阻塞
正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。

(4) 阻塞→就绪
处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。

2.3多进程方式编程

from multiprocessing import Process
import os
import time# 子进程要执行的代码
def task_process(delay):num = 0for i in range(delay*10000000):num+=iprint(f"进程pid为 {os.getpid()},执行完成")if __name__=='__main__':print( '父进程pid为 %s.' % os.getpid())t0 = time.time()task_process(3)task_process(3)t1 = time.time()print(f"顺序同步方式执行耗时 {t1-t0} ")p0 = Process(target=task_process, args=(3,))p1 = Process(target=task_process, args=(3,))t2 = time.time()p0.start();p1.start()p0.join();p1.join()t3 = time.time()print(f"多进程并发执行耗时 {t3-t2}")

在这里插入图片描述

三、线程(Thread)

3.1 线程的引入

    早期的多任务操作系统,以进程为单位管理各个程序的运行以及计算机资源的分配和回收,进一步提高了计算机资源的利用率。但随着计算机硬、软件的发展,人们发现还可以做进一步优化,例如:

  • 操作系统将 CPU 资源从一个进程分配给另一个进程时,开销较大;
  • 各个进程占用的内存空间是相互独立的,大大增加了进程间通信的实现难度;
  • 一个进程可能会执行多个任务,当某个任务因 I/O 操作暂停执行时,其他任务将无法执行。

在计算机软、硬件快速发展,人们计算机运行效率的要求越来越高的大背景下,“线程”应运而生。

3.2 线程概念

    线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务,比如一段程序、一个函数等。

    线程和进程之间的关系,类似于工厂和工人之间的关系,进程好比是工厂,线程就如同工厂中的工人。一个工厂可以容纳多个工人,工厂负责为所有工人提供必要的资源(电力、产品原料、食堂、厕所等),所有工人共享这些资源,每个工人负责完成一项具体的任务,他们相互配合,共同保证整个工厂的平稳运行。

每个进程执行前,操作系统都会为其分配所需的资源,包括要执行的程序代码、数据、内存空间、文件资源等。一个进程至少包含 1 个线程,可以包含多个线程,所有线程共享进程的资源,各个线程也可以拥有属于自己的私有资源。
在这里插入图片描述

3.3 多线程编程

多线程概念:

一个进程中拥有多(≥2)个线程,线程之间相互协作、共同执行一个应用程序。

通常将以“多线程”方式编写的程序称为“多线程程序”,将编写多线程程序的过程称为“多线程编程”,将拥有多个线程的进程称为“多线程进程”。

当进程中仅包含 1 个执行程序指令的线程时,该线程又称“主线程”,这样的进程称为“单线程进
程”。

很多应用程序(软件)都是多线程程序,例如 QQ 具备同时和多人聊天的能力、迅雷具备同时下载多个资源的能力、很多杀毒软件可以同时开启杀毒、清理垃圾、电脑加速等功能。

3.4 GIL对多线程的影响

import threading, timedef my_counter():total = 100_000_000i = 0for _ in range(total):i = i+1if i % (total/10) == 0:print(f"当前进度:{i/total:.2%} ")return Truedef main1():thread_ary = {}start = time.time()for tid in range(2):t = threading.Thread(target=my_counter)t.start()t.join()  # 第1次循环,join方法引起主线程阻塞,但第2个线程并没有启动,所以2个线程是顺序执行的end = time.time()print(f"单线程顺序执行方式:total_time: {end - start:.2f}")def main2():thread_ary = {}start = time.time()for tid in range(2):t = threading.Thread(target=my_counter)t.start()thread_ary[tid] = tfor i in range(2):thread_ary[i].join() # 两个线程均已启动,所以两个线程是并发的end = time.time()print(f"多线程并发执行方式:total_time: {end-start:.2f}")if __name__ == "__main__":main1()main2()
100_000_000
单线程顺序执行方式:total_time: 36.82
多线程并发执行方式:total_time: 36.97
1_000_000_000
单线程顺序执行方式:total_time: 368.88
多线程并发执行方式:total_time: 366.76

3.5 GIL是否意味着线程安全

并不是。GIL是用来保护Python解释器的线程安全,不是用来保护用户线程的线程安全,软件开发人员需要自己解决。

解释器本身有大量的变量,是需要进行保护的。假设没有GIL时,两个线程都需要抛出异常,那么异常应该如何存储和处理,改变解释器的状态,就成了问题。GIL在此环境里就限制了解释器本身只有一个线程处于运行中,任意Python解释器级别操作都是串行的,使得任一时间都只能有最多一个语句抛出异常。于是异常相关的共享变量就得到了保护。但对于Python程序里,用户创建的线程,就需要程序员自己利用threading里的设施来进行并发保护。因为一个Python语句,往往对应了底层的多个Python解释器操作,这些操作的执行顺序可能会被操作系统的抢占式多任务打乱的。所以不得不进行保护。

举个例子,打印语句:
print("hello world")
其底层就至少可以分为3个操作,现实中可能操作更多:
sys.sdout.write("hello world")
sys.stdout.write("\n")
sys.stdout.flush()

所以在多个线程一起执行 print(“hello world”) 时,屏幕上就可能看到同一行里多个hello world,这就是语句内部的操作被抢占式多任务打乱的结果。

四、协程(Coroutine)

4.1 协程概念

是一个更小的概念,它是位于线程内部,完全受程序所控制,开销小,协程,又称微线程,也称为用户级线程,在不开辟线程的基础上完成多任务,也就是在单线程的情况下完成多任务,多个任务按照一定顺序交替执行,它的特点就是运行效率极高。


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
在这里插入图片描述

http://www.lryc.cn/news/467192.html

相关文章:

  • 嵌入式工程师成长之路(1)——元件基础(完整版)
  • 在Ubuntu 20.04 上安装 CoppeliaSim
  • pulseaudio的相关操作(二)
  • Selenium自动化测试工具
  • 优化UVM环境(九)-将interface文件放在env pkg外面
  • mysql 主从安装
  • 【C++刷题】力扣-#121-买卖股票的最佳时机
  • Python量化交易(二):金融市场的基础概念
  • Java方法的递归调用
  • JavaScript 第30章:综合项目
  • GB/T28181-2022规范解读、应用场景和技术实现探究
  • Docker容器间链路管理
  • python画图|在三维空间的不同平面上分别绘制不同类型二维图
  • 与ai一起作诗(《校园清廉韵》)
  • python matplotlib
  • 秋招面试题记录_半结构化面试
  • Java项目-基于springboot框架的疫苗接种管理系统项目实战(附源码+文档)
  • Android 12.0进程保活白名单功能实现
  • vscode 功能、设置备忘
  • 错误 Failed to connect to xx.xx.xx.xx port xx: No route to host
  • Redis环境的搭建
  • Git Push(TODO)
  • Java工具类--截至2024常用http工具类分享
  • C#学习笔记(五)
  • 视频云存储/音视频流媒体视频平台EasyCVR视频汇聚平台在欧拉系统中启动失败是什么原因?
  • spring源码中的,函数式接口,注解@FunctionalInterface
  • 分布式系统中的Session共享:实现跨服务器的用户登录信息同步
  • 【LeetCode每日一题】——1588.所有奇数长度子数组的和
  • 自定义多级联动选择器指南(uni-app)
  • RHCE笔记-SSH服务