线程和进程
线程和进程定义
在实现了线程的操作系统中,线程是操作系统能够进行运算调度的最小单位。它被包含在进程中,是进程中的实际运作单位。一个程序的执行实例就是一个进程。
- 进程(Process):计算机中的程序关于某数据集合上的一次运行行动,是系统进行资源分配和调度的基本单位(管理资源用的), 是操作系统解构的基础。
- 进程和程序的关系:程序是源代码编译后的文件,而这些文件存放在磁盘上。当程序被操作系统加载到内存中,就是进程,进程中存放指令和数据(资源), 它也是线程的容器。
- Linux进程有父进程和子进程,Windows的进程是平等关系。
- 线程:有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元,一个标注的线程有线程ID,当前指令指针(PC)、寄存器集合和堆、栈组成。在许多系统中,创建一个线程比创建一个进程快10-100倍。
线程和进程的资源问题
现代操作系统提出进程的概念, 每一个进程都认为自己独占所有的计算机硬件资源。
进程就是独立的王国,进程间不可以随便的共享数据。(可以进程间通讯,代价比较高)
线程就是省份,同一个进程内的线程可以共享进程的资源,每一个线程拥有自己独立的堆栈。
线程的状态
状态 | 含义 |
就绪(Ready) | 线程能够运行,但在等待被调度。可能线程刚刚 |
运行(Running) | 线程正在运行 |
阻塞(Blocked) | 线程等待外部事件发生而无法运行,如I/O操作 |
终止(Terminated) | 线程完成,或退出,或被取消 |
python中的进程和线程
运行程序会启动一个解释器进程,线程共享一个解释器进程。
Python线程开发
Python的线程开发使用标准库threading.
进程靠线程执行代码, 至少有一个主线程, 其它线程是工作线程.
主线程是第一个启动的线程.
- 父线程: 如果线程A中启动了一个线程B, A就是B的父线程
- 子线程: B就是A的子线程
Thread类
参数名 | 含义 |
target | 线程调用的对象, 就是目标函数 |
name | 为线程起个名字 |
args | 为目标函数传递实参, 元组 |
kwargs | 为目标函数传递关键字参数, 字典 |
deamon | ㅤ |
线程启动
通过threading.Thread创建一个线程对象, target是目标函数, 可以使用name为线程指定线程名称.
但是线程没有启动, 需要调用start方法.
线程之所以执行函数, 是因为线程中就是要执行代码的, 而最简单的代码封装就是函数, 所以还是函数调用.
函数执行完, 线程也就退出了.
那么, 如果不让线程退出, 或者让线程一直工作怎么办呢?
线程退出
Python没有提供线程退出的方法, 线程在下面情况时退出:
- 线程函数内语句执行完毕
- 线程函数中抛出未处理的异常
注: 工作线程即使异常退出, 主线程依然可以运行.
Python的线程没有优先级, 没有线程组的概念, 也不能被销毁, 停止, 挂起, 那也就没有恢复, 中断了.
线程的传参
线程传参和函数传参没什么区别, 本质上就是函数传参.
threading模块的属性和方法
名称 | 含义 |
current_thread() | 返回当前线程对象 |
main_thread() | 返回主线程对象 |
active_count() | 当前处于alive转态的线程数 |
enumerate() | 返回所有活着的线程的列表, 不包括已经终止的线程和未开始的线程 |
get_ident() | 返回当前线程的ID, 非0整数 |
active_count(), enumerate()方法返回的值还包括主线程.
Thread实例的属性和方法
名称 | 含义 |
name | 只是一个名字, 只是个标识符, 名称可以重名. getName(), setName()获取, 设置这个名词 |
ident | 线程ID, 它是非0整数. 线程启动后才会有ID, 否则为None. 线程退出, 此ID依旧可以访问. 此ID可以重复使用. |
is_alive() | 返回线程是否活着, 是为True, 否为False |
注意:线程名name可以重复, 但是线程ID是不能重复的, 但可以在线程退出后再利用.
从上面的例子还可以看出, 一个线程只能被运行一次, 如果线程结束了, 那么再次将这个线程对象重启是会报错.
名称 | ㅤ |
start() | 启动线程. 每个线程必须且只能执行该方法一次 |
run() | 运行线程函数 |
为了掩饰, 派生一个Thread的子类