本篇为学习笔记,用途为记录以及复习。
内容主要参考:https://www.cnblogs.com/whatisfantasy/p/6440585.html 作者:morra
1 概念梳理:
1.1 进程
一个程序的执行实例就是一个进程。每一个进程提供执行程序所需的所有资源。(进程本质上是资源的集合。)一个进程有一个虚拟的地址空间、可执行的代码、操作系统
的接口、安全的上下文(记录启动该进程的用户和权限等等)、唯一的进程ID,环境变量,优先级类,最小和最大的工作空间(内存空间),还要有至少一个线程。
每一个进程启动时都会最先产生一个线程,即主线程。然后主线程会再创建其他的子线程。
与进程相关的资源包括:
- 内存页(同一个进程中的所有线程共享同一个内存空间)
- 文件描述符(eg. open sockets)
- 安全凭证(eg. 启动该进程的用户ID)
1.2 线程
1.1.1 什么是线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个
线程,每条线程并行执行不同的任务。一个
线程是一个execution context(执行上下文),即一个cpu执行是所需的一串指令。
1.1.2 线程的工作方式
假设你正在读一本书,没有读完,你想休息一下,但是你想在回来时恢复到当时读的具体进度。有一个方法就是记下页数、行数与字数这三个数值,这些数值就是execution context。如果你的室友在你休息的时候,使用相同的方法读这本书。你和她只需要这三个数字记下来就可以在交替的时间共同阅读这本书了。
线程的工作方式与此类似。CPU会给你一个在同一时间能够做多个运算的幻觉,实际上它在每个运算上只花了极少的时间,本质上CPU同一时刻只干了一件事。它能这样做
就是因为它有每个运算的execution context。就像你能够和你朋友共享同一本书一样,多任务也能共享同一块CPU。
1.3 进程和线程区别
1.同一个进程中的线程共享同一内存空间,但是进程之间是独立的。
2.同一个进程中的所有线程的数据是共享的(线程通讯),进程之间的数据是独立的。
3.对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
4.线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。
5.同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。
6.创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。
7.一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
8.线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。
1.4 总结
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,
打开一个Word就启动了一个Word进程。
有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,
我们把进程内的这些“子任务”称为线程(Thread)。
2 多线程:
2.1 线程常用方法
1. start() 线程准备就绪,等待CPU调度
2. setName() 为线程设置名称
3. getName() 获取线程名称
4. setDaemon(True) 设置为守护线程
5. join() 逐个执行每个线程,执行完毕后继续往下执行
6. run() 线程被CPU调度后自动执行线程对象的run方法,如果想自定义线程类,直接重写run方法就行了。
2.1.1 Thread类
1. 普通创建方式
1 1 # 新线程执行的代码 2 2 def loop(): 3 3 print('thread %s is running...' % threading.current_thread().name) 4 4 n = 0 5 5 while n < 5: 6 6 n += 1 7 7 print('thread %s >>> %s' % (threading.current_thread().name, n)) 8 8 time.sleep(1) 9 9 print('thread %s ended.' % threading.current_thread().name) 10 10 11 11 print('thread %s is running...' % threading.current_thread().name) 12 12 t = threading.Thread(target = loop, name = 'LoopThread') 13 13 t.start() 14 14 t.join() 15 15 print('thread %s ended.' % threading.current_thread().name) 16 16 17 17 """ 18 任何进程默认就会启动一个线程,我们把该线程称为主线程(MainThread)主线程又可以启动新线程, 19 Python中的Threading模块有一个current_thread()函数,它永远返回当前线程的实例子线程的名字在创建时指定, 20 我们用LoopThread命名子线程。名字仅仅在打印时用来显示,完全没有其他意义,如果不起名字Python就自动给线程命名 21 为Thread-1,Thread-2 22 """
1 thread MainThread is running... 2 thread LoopThread is running... 3 thread LoopThread >>> 1 4 thread LoopThread >>> 2 5 thread LoopThread >>> 3 6 thread LoopThread >>> 4 7 thread LoopThread >>> 5 8 thread LoopThread ended. 9 thread MainThread ended.
1 import threading 2 import time 3 4 def run(n): 5 print('task', n) 6 time.sleep(1) 7 print('2s') 8 time.sleep(1) 9 print('1s') 10 time.sleep(1) 11 print('0s') 12 time.sleep(1) 13 14 # 创建t1,t2两个线程 15 t1 = threading.Thread(target = run, args = ('t1',)) 16 t2 = threading.Thread(target = run, args = ('t2',)) 17 t1.start() 18 t2.start()
2. 继承threading.Thread来自定义线程类
其本质是重构Thread类中的run方法。
1 import threading