关于多进程与多线程基础的学习,必要的概念很多,但我觉得不着急去一次性去死记

多进程与多线程的基础使用很简单,几个方法只需上手 运行一下 文中的代码就可以很快熟悉起来

进阶部分篇幅有点长,放在了另一篇文章:
Python之路 34:万字总结:并发与并行、锁(GIL、同步锁、死锁与递归锁)、信号量、线程队列、生消模型、进程(基础使用、进程通信、进程池、回调函数)、协程

一、操作系统的历史

进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展开的。

并发编程(线程 进程 协程) - Yuan先生 - 博客园 (cnblogs.com)

二、进程与线程的概念

进程:最小的资源单元

线程:最小执行单元

2.1、进程

(1)概念

进程:三个相似的答案

  • 本质上就是一段程序的运行过程(进程是一个抽象的概念)
  • “进程就是一个程序在一个数据集上的一次动态执行的过程”
  • 正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。

进程的组成:

  • 程序
  • 数据集
  • 进程控制块
假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源。是不是在程序A读取数据的过程中,让程序B去执行,当程序A读取完数据之后,让程序B暂停,然后让程序A继续执行?当然没问题,但这里有一个关键词:切换既然是切换,那么这就涉及到了状态的保存,状态的恢复,加上程序A与程序B所需要的系统资源(内存,硬盘,键盘等等)是不一样的。自然而然的就需要有一个东西去记录程序A和程序B分别需要什么资源,怎样去识别程序A和程序B等等,所以就有了一个叫进程的抽象进程定义:进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。举一例说明进程:想象一位有一手好厨艺的计算机科学家正在为他的女儿烘制生日蛋糕。他有做生日蛋糕的食谱,厨房里有所需的原料:面粉、鸡蛋、糖、香草汁等。在这个比喻中,做蛋糕的食谱就是程序(即用适当形式描述的算法)计算机科学家就是处理器(cpu),而做蛋糕的各种原料就是输入数据。进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等一系列动作的总和。现在假设计算机科学家的儿子哭着跑了进来,说他的头被一只蜜蜂蛰了。计算机科学家就记录下他照着食谱做到哪儿了(保存进程的当前状态),然后拿出一本急救手册,按照其中的指示处理蛰伤。这里,我们看到处理机从一个进程(做蛋糕)切换到另一个高优先级的进程(实施医疗救治),每个进程拥有各自的程序(食谱和急救手册)。当蜜蜂蛰伤处理完之后,这位计算机科学家又回来做蛋糕,从他离开时的那一步继续做下去。

(2)进程与程序的区别

程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。

注意:

​ 同一个程序执行两次,那也是两个进程,比如打开腾讯视频,虽然都是同一个软件,但是一个可以播放《生活大爆炸》,一个可以播放《老友记》。

2.2、线程 Thead

(1)概念

​ 线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一件事的缺陷,使得进程内并发成为可能

​ 多线程(即多个控制线程):在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。

​ 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。

注意:

1 一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器)2 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。3 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 4 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

(2)线程的创建开销小

1、创建进程的开销要远大于线程?

如果我们的软件是一个工厂,该工厂有多条流水线,流水线工作需要电源,电源只有一个即cpu(单核cpu)

一个车间就是一个进程,一个车间至少一条流水线(一个进程至少一个线程)

创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线)

而建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小

2、进程之间是竞争关系,线程之间是协作关系?

车间直接是竞争/抢电源的关系,竞争(不同的进程直接是竞争关系,是不同的程序员写的程序运行的,迅雷抢占其他进程的网速,360把其他进程当做病毒干死)
一个车间的不同流水线式协同工作的关系(同一个进程的线程之间是合作关系,是同一个程序写的程序内开启动,迅雷内的线程是合作关系,不会自己干自己)

(3)线程与进程的区别

  1. Threads share the address space of the process that created it; processes have their own address space.
  2. Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
  3. Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
  4. New threads are easily created; new processes require duplication of the parent process.
  5. Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
  6. Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
  1. 线程共享创建它的进程的地址空间;进程有自己的地址空间。
  2. 线程可以直接访问其进程的数据段;进程有自己的父进程数据段的副本。
    3.线程可以直接与进程中的其他线程通信;进程必须使用进程间通信来与同级进程通信。
  3. 新线程很容易创建;新进程需要复制父进程。
  4. 线程可以对同一进程的线程进行相当大的控制;进程只能对子进程进行控制。
  5. 主线程的改变(取消,优先级的改变,等等)可能会影响进程中其他线程的行为;对父进程的更改不会影响子进程。

(4)为什么要用多线程

多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:

  1. 多线程共享一个进程的地址空间
  2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
  3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
  4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)

三、并发与并行

并行处理(Parallel Processing)是计算机系统中能同时执行两个或更多个处理的一种计算方法。并行处理可同时工作于同一程序的不同方面。并行处理的主要目的是节省大型和复杂问题的解决时间。

并发处理(concurrency Processing):指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机(CPU)上运行,但任一个时刻点上只有一个程序在处理机(CPU)上运行

简单来说:

  • 并发:指系统具有处理多个任务的能力
  • 并行:指系统具有 同时 处理多个任务的能力

并发的关键是你有处理多个任务的能力,不一定要同时。

并行的关键是你有同时处理多个任务的能力。

所以说,并行是并发的子集

无论是并行还是并发,在用户看来都是’同时’运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务

并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)

并行: 并行:同时运行,只有具备多个cpu才能实现并行

​ 单核下,可以利用多道技术,多个核,每个核也都可以利用多道技术(多道技术是针对单核而言的

​ 有四个核,六个任务,这样同一时间有四个任务被执行,假设分别被分配给了cpu1,cpu2,cpu3,cpu4,

​ 一旦任务1遇到I/O就被迫中断执行,此时任务5就拿到cpu1的时间片去执行,这就是单核下的多道技术

​ 而一旦任务1的I/O结束了,操作系统会重新调用它(需知进程的调度、分配给哪个cpu运行,由操作系统说了算),可能被分配给四个cpu中的任意一个去执行

四、线程

threading模块

官网链接:threading — Thread-based parallelism — Python 3.10.2 documentation

先上总结

常用的方法:

  • t1 = threading.Thread(target=函数名,args=(传入变量(如果只有一个变量就必须在后加上逗号),),name=取一个线程名) # 把一个线程实例化给t1,这个线程负责执行target=你写的函数名
  • t1.start() # 执行启动这个线程
  • t1.join() # 必须要等t1这个子线程执行完成,即使主进程结束了也不会退出程序
  • t1.setDeamon(True) # :当你的主线程执行完毕后,不管子线程有没有执行完成都退出主程序,注意不能和t1.join()一起使用。
  • threading.current_thread().name # 打印出线程名

其他方法:

Thread实例对象的方法

  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

threading模块提供的一些方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线

程启动后、结束前,不包括启动前和终止后的线程。

  • threading.activeCount(): 返回正在运行的线程数量,与
  • len(threading.enumerate())有相同的结果。

4.1、线程的调用

开启线程有两种方式

方法一:threading.Thread

from threading import Thread
import timedef sayhi(name):time.sleep(2)print('hello %s ' % name)if __name__ == '__main__':t = Thread(target=sayhi, args=('coder',))t.start()print('主线程')

运行结果:

主线程
hello coder 进程已结束,退出代码为 0

可以看到程序先输出了 “主线程” ,2s 后输出 “hello coder ”

方法二:通过继承的方式

from threading import Thread
import timeclass Sayhi(Thread):def __init__(self, name):super().__init__()self.name = namedef run(self):time.sleep(2)print('hello %s ' % self.name)if __name__ == '__main__':t = Sayhi('coder')t.start()print('主线程')

运行结果:

主线程
hello coder 进程已结束,退出代码为 0

可以看到程序先输出了 “主线程” ,2s 后输出 “hello coder ”

4.2、join方法

t1.join() # 必须要等t1这个子线程执行完成,即使主进程结束了也不会退出程序

注意一下两个示例

示例一:

import threading
import timedef hi():print("hi,time1")time.sleep(3)print("hi,time2")def hello():print("hello.time1")time.sleep(1)print("hello.time2")if __name__ == "__main__":fun1 = threading.Thread(target=hi, args=())  # 不可写为 args=Nonefun2 = threading.Thread(target=hello, args=())fun1.start()fun2.start()fun1.join()fun2.join()print("end")

运行结果:

hi,time1
hello.time1
hello.time2
end
hi,time2进程已结束,退出代码为 0

示例二:

稍稍修改一下

import threading
import timedef hi():print("hi,time1")time.sleep(3)print("hi,time2")def hello():print("hello.time1")time.sleep(1)print("hello.time2")if __name__ == "__main__":fun1 = threading.Thread(target=hi, args=())  # 不可写为 args=Nonefun2 = threading.Thread(target=hello, args=())fun1.start()fun1.join()fun2.start()fun2.join()print("end")

运行结果:

hi,time1
hi,time2
hello.time1
hello.time2
end进程已结束,退出代码为 0

4.3、setDaemon方法和继承式调用

t1.setDeamon(True) # 当你的主线程执行完毕后,不管子线程有没有执行完成都退出主程序,注意不能和t1.join()一起使用。

这就是所谓的:守护线程,守护着主线程运行完毕后伴随着被销毁

示例一:

from threading import Thread
import timedef sayhi(name):print("t1 start\n")time.sleep(2)print('hello %s ' % name)if __name__ == '__main__':t = Thread(target=sayhi, args=('coder',))t.setDaemon(True)  # 必须在t.start()之前设置t.start()print('主线程')print(t.is_alive())

运行结果:

t1 start
主线程True进程已结束,退出代码为 0

示例二:

这个例子比较迷惑人

from threading import Thread
import timedef foo():print("t1 start")time.sleep(1)print("t1 end")def bar():print("t2 start")time.sleep(3)print("t2 end")if __name__ == '__main__':t1 = Thread(target=foo)t2 = Thread(target=bar)t1.daemon = Truet1.start()t2.start()print("\n主线程\n")

运行结果:

t1 start
t2 start主线程t1 end
t2 end进程已结束,退出代码为 0

大家可能回想为啥设置了守护线程,咋就没作用呢

原因:t1设置了守护线程,t2没设置啊,打印完“主线程”后t2仍在执行,所以t1这个子线程就没有中断

如果你把函数bar()中的sleep(3)改成sleep(0.5),运行结果就变成了:

t1 start
t2 start
主线程t2 end进程已结束,退出代码为 0

因为t2不是守护线程,主线程结束了,主线程和t2结束后,不管t1有没有结束,程序到此终止

4.4、其他方法

Thread实例对象的方法 - isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名。threading模块提供的一些方法:- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。- threading.activeCount(): 返回正在运行的线程数量,与
- len(threading.enumerate())有相同的结果。

五、进程

仅看使用方法,跟线程几乎一样,还是那几个功能

5.1、进程的调用

方法一:

from multiprocessing import Process
import timedef func(name):time.sleep(1)print('hello', name, time.ctime())if __name__ == '__main__':p_list = []for i in range(3):p = Process(target=func, args=('coder',))p_list.append(p)p.start()for i in p_list:p.join()print('end')

运行结果:

hello coder Thu Feb  3 14:45:55 2022
hello coder Thu Feb  3 14:45:55 2022
hello coder Thu Feb  3 14:45:55 2022
end进程已结束,退出代码为 0

方法二:

from multiprocessing import Process
import timeclass MyProcess(Process):def __init__(self):super(MyProcess, self).__init__()# self.name = namedef run(self):time.sleep(1)print('hello', self.name, time.ctime())if __name__ == '__main__':p_list = []for i in range(3):p = MyProcess()p.start()p_list.append(p)for p in p_list:p.join()print('end')

运行结果:

hello MyProcess-2 Thu Feb  3 14:48:28 2022
hello MyProcess-1 Thu Feb  3 14:48:28 2022
hello MyProcess-3 Thu Feb  3 14:48:28 2022
end进程已结束,退出代码为 0

用PID了解父进程子进程

from multiprocessing import Process
import os
import timedef info(title):print("title:", title)print('parent process:', os.getppid())  # os.getppid() ==》 父进程的PIDprint('process id:', os.getpid())  # os.getpid() ==》 本身的PIDdef f(name):info('function f')print('hello', name)if __name__ == '__main__':info('main process line')time.sleep(1)print("------------------")p = Process(target=info, args=('coder',))p.start()p.join()

运行结果:

title: main process line
parent process: 21960
process id: 7088
------------------
title: coder
parent process: 7088
process id: 14012进程已结束,退出代码为 0

5.2、进程的相关方法

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])group: 线程组,目前还没有实现,库引用中提示必须是None; target: 要执行的方法; name: 进程名; args/kwargs: 要传入方法的参数。

实例方法:

  is_alive():返回进程是否在运行。join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。start():进程准备就绪,等待CPU调度run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。terminate():不管任务是否完成,立即停止工作进程

属性:

  daemon:和线程的setDeamon功能一样name:进程名字。pid:进程号。

Python之路 33:进程与线程概念及基础使用相关推荐

  1. python(40)- 进程、线程、协程及IO模型

    一.操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式:向下管理硬件,向上提供接口. 操作系统进行进程切换:1.出现IO操作:2.固定时间. 固定时间很短,人感受不到.每一个应用层运行起 ...

  2. Python自学笔记之进程和线程

    在使用计算机或者手机的时候可以发现他们都能同时使用多个程序,这里就要涉及到多线程编程,多线程编程能够帮助我们合理的分配并最高效的利用资源. 进程 概念进程(Process)是计算机中的程序关于某数据集 ...

  3. Python学习笔记:进程和线程(承)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  4. Python学习笔记:进程和线程(起)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  5. python 协程、进程、线程_Python的进程、线程和协程 · Donzy’s Blogs

    0.前言 在计算机技术领域,吞吐量(throughput)是计算机在指定的一段时间内完成编程技术如何影响.本文主要讨论Python的多进程.多线程及协程等编程技术在不同场景下对系统吞吐量的影响. 1. ...

  6. python 协程、进程、线程_Python进程、线程、协程之间的关系

    一.从操作系统角度 操作系统处理任务, 调度单位是 进程 和 线程 . 1.进程: 表示一个程序的执行活动 (打开程序.读写程序数据.关闭程序) 2.线程: 执行某个程序时, 该进程调度的最小执行单位 ...

  7. python 协程、进程、线程_Python 中的进程、线程、协程

    1. 进程 进程是正在运行的程序实例,是内核分配资源的最基本的单元.进程拥有自己独立的堆和栈,独立的地址空间,资源句柄.进程由 OS 调度,调度开销较大,在并发的切换过程效率较低. Python 提供 ...

  8. 并发和多线程(一)并发、进程、线程概念

    一.并发.进程.线程的基本概念和综述 1.1 并发 两个或者更多的任务(独立的活动)同时发生(进行):一个程序同时执行多个独立的任务: 以往计算机,单核cpu(中央处理器):某一个时刻只能执行一个任务 ...

  9. python——通信原理,进程与线程

    一.网络编程 1.计算机网络 将地理位置不同的具有独立功能地多台计算机及其外部设备,通过通信线路连接起来,在协议的管理和协调下,实现资源共享和信息传递. 网络编程:用来实现网络互连的不同计算机运行程序 ...

最新文章

  1. 暑假想打比赛,小白怎么从0入门?
  2. 值得收藏!7个值得下载的软件,让人大开眼界!
  3. 驰骋工作流引擎设计系列05 启动流程设计
  4. 拼多多面试真题:如何用 Redis 统计独立用户访问量!
  5. 避障机器人程序c语言,基于51单片机小车寻迹、避障源程序(注释很详细)
  6. C++ Primer 5th笔记(chap 13 拷贝控制)拷贝赋值函数
  7. asp.net用户登录 用户验证
  8. date -d的灵活应用
  9. eclipse定制化配置调优、初始化配置指南、可以解决启动慢等问题
  10. 阿里云飞天AI加速器+Serverless容器,帮助图森未来提升资源利用率
  11. JDBC系列(二):JDBC代码的编写步骤
  12. 将RP文件导出为HTML文件
  13. Kettle数据抽取实战之四:网页数据抽取
  14. 接入阿里云云呼叫中心
  15. XXS靶场haozi
  16. 由浅入深玩转华为WLAN—12安全认证配置(5)Portal认证,外置Protal服务器TSM对接(网页认证)
  17. linux中如何查看mac地址
  18. 以太坊区块链浏览器(一)拿来就用主义
  19. CHINA TOP国家杯:用电子竞技搭建中国文化走出去的平台
  20. Introduction to Programming I

热门文章

  1. 南阳百里奚计算机学校,南阳之子 百里奚
  2. 云南省二级c计算机考试试题,2015云南省计算机等级考试试题 二级C试题最新考试试题库(完整版)...
  3. WiFi模块(ESP8266)获取时间、天气API AT指令串口调试
  4. Java调试大法,来了~
  5. 计算机毕业设计之java+springboot基于vue的人事管理系统-员工管理系统
  6. TCP/UDP 端口
  7. 安卓电子书格式_如何将电子书导入kindle App?
  8. 安全合规--40--基于欧美法律法规的企业隐私合规体系建设经验总结(四)
  9. 阿里云网站备案申请被驳回怎么办?
  10. ios 编译时报 Could not build module xxx 的解决方法尝试