一、多线程
二、进程
三、线程
四、并行执行
五、进程、线程和并行执行
六、多线程编程
一、多线程
多线程是指在一个进程内同时执行多个线程的并发执行方式。每个线程是独立的执行单元,它们共享相同的地址空间,但拥有各自的寄存器和栈。多线程的使用可以提高程序的并发性,允许在同一程序中执行多个任务,使程序更加响应和效率。
以下是多线程的一些概念和关键特点:
-
线程: 线程是操作系统能够进行运算调度的最小单位。在一个进程中可以有多个线程,它们共享进程的资源。
-
进程: 进程是程序的一次执行,是资源分配的最小单位。一个进程可以包含多个线程。
-
并发性: 多线程使得多个任务可以同时执行,提高了程序的并发性。每个线程都可以独立执行自己的任务。
-
共享内存: 多线程在同一进程中共享相同的地址空间,因此它们可以方便地共享数据。
-
线程安全: 当多个线程同时访问共享数据时,可能发生竞态条件(Race Condition)。为了避免数据不一致性,需要采取措施保证线程安全。
-
同步: 同步是为了防止多个线程同时访问共享资源,以避免竞态条件。常见的同步机制包括互斥锁、信号量、条件变量等。
-
死锁: 死锁是指两个或多个线程相互等待对方释放资源,从而导致程序无法继续执行。
-
线程池: 线程池是一种线程管理机制,通过事先创建一些线程并放入池中,可以重复使用这些线程来执行任务,提高效率。
-
守护线程: 守护线程是在程序后台运行的线程,当所有的非守护线程都结束时,守护线程会被强制终止。
在多线程编程中,需要注意线程间的同步和互斥,以及对共享资源的安全访问。各种编程语言提供了多线程的支持,例如Python中的threading
模块,Java中的java.util.concurrent
包。
二、进程
进程是计算机中的一个基本概念,指的是正在运行的程序的实例。每个进程都是一个独立的执行单元,拥有自己的内存空间、寄存器集合和系统资源。操作系统通过进程的调度来实现多任务并发执行。
以下是一些关于进程的基本概念和特点:
-
程序 vs 进程: 程序是静态的,是存储在磁盘上的可执行文件;而进程是程序的一次执行,是在内存中运行的实体。
-
进程状态: 一个进程可以处于运行、就绪、阻塞等状态。运行状态表示进程正在执行指令,就绪状态表示进程已经准备好执行,但还未获得 CPU 时间,阻塞状态表示进程等待某个事件的发生。
-
进程控制块(PCB): 每个进程都有一个进程控制块,用于保存进程的状态信息、程序计数器、寄存器值等。
-
进程间通信(IPC): 不同的进程之间可能需要进行通信和数据交换。常见的 IPC 方法包括管道、消息队列、信号量、共享内存等。
-
进程调度: 操作系统通过进程调度算法来确定下一个执行的进程,以实现多任务并发执行。
-
父子进程关系: 进程可以通过创建子进程来实现并发执行。父进程创建子进程后,它们共享一些资源,但也可以有独立的资源。
-
进程组和会话: 进程组是一组相互关联的进程的集合,会话是一个或多个进程组的集合。进程组和会话的概念主要与作业控制和终端相关。
-
守护进程: 守护进程是在后台运行的进程,通常在系统启动时启动,独立于终端,用于执行一些系统任务。
-
死锁: 死锁是指两个或多个进程相互等待对方释放资源,导致它们都无法继续执行。
-
多进程 vs 多线程: 多进程是指一个程序同时运行多个独立的进程,每个进程有自己的地址空间;多线程是指在同一进程内同时执行多个线程,它们共享相同的地址空间。
进程是操作系统中的核心概念之一,对于实现多任务、资源管理和系统稳定性都具有重要作用。
三、线程
线程是操作系统能够进行运算调度的最小单位,是进程中的执行单元。一个进程可以包含多个线程,它们共享进程的资源,但拥有各自的寄存器、栈和程序计数器。线程之间的切换更为轻量级,相比于进程而言,线程更加灵活。
以下是关于线程的一些基本概念和特点:
-
并发执行: 多个线程可以同时执行,从而提高程序的并发性。每个线程都是独立的执行单元,可以执行自己的任务。
-
共享内存: 在同一进程中的线程共享相同的地址空间,因此它们可以方便地共享数据。但共享数据时需要考虑线程安全性。
-
线程状态: 一个线程可以处于运行、就绪、阻塞等状态。运行状态表示线程正在执行指令,就绪状态表示线程已经准备好执行,阻塞状态表示线程等待某个事件的发生。
-
线程局部存储(TLS): 每个线程可以拥有自己的局部存储空间,这样线程之间的数据隔离就更好了。
-
线程同步: 当多个线程同时访问共享资源时,可能发生竞态条件(Race Condition)。为了避免数据不一致性,需要采取措施保证线程安全,例如使用锁、信号量等。
-
用户级线程 vs 内核级线程: 用户级线程是由用户空间的线程库实现,内核并不知道线程的存在;内核级线程是由操作系统内核管理的线程,更加稳定但开销较大。
-
轻量级线程 vs 重量级线程: 轻量级线程的创建和切换开销较小,由用户空间的线程库实现;重量级线程则由操作系统内核实现,开销相对较大。
-
线程池: 线程池是一种线程管理机制,通过事先创建一些线程并放入池中,可以重复使用这些线程来执行任务,提高效率。
-
死锁: 死锁是指两个或多个线程相互等待对方释放资源,导致程序无法继续执行。
线程是并发编程的基本单位,用于实现多任务并发执行。多线程的使用可以提高程序的响应性,但也需要注意线程安全和同步的问题。不同的编程语言提供了多线程的支持,例如Python中的threading
模块,Java中的java.lang.Thread
类。
四、并行执行
并行执行指的是多个任务在同一时刻同时执行,通常是利用多个处理器、多核心或多计算节点来实现的。并行性是计算机科学中的一个重要概念,可以提高程序的性能和效率。
以下是关于并行执行的一些基本概念和特点:
-
任务分解: 将一个大任务分解成多个小任务,每个小任务可以在独立的处理器或核心上执行。这样可以提高任务的并行度。
-
并行计算模型: 有多种并行计算模型,包括数据并行、任务并行、流水线并行等。不同的应用场景可能适用不同的并行计算模型。
-
多处理器系统: 多处理器系统包含多个处理器,可以同时执行多个任务。每个处理器有自己的寄存器和缓存,但它们共享内存。
-
多核处理器: 多核处理器在同一芯片上集成了多个处理核心,每个核心可以执行独立的任务。多核处理器在单个芯片上提供了更高的计算密度。
-
向量化和SIMD: 向量化是指在同一时刻对多个数据执行相同的操作,SIMD(Single Instruction, Multiple Data)是一种并行计算的技术,通过在一个时钟周期内执行相同的指令来处理多个数据。
-
并行算法: 并行算法是为并行计算设计的算法,能够充分利用多处理器或多核处理器的性能。
-
任务并发 vs 数据并发: 任务并发是指多个任务同时执行,数据并发是指在同一任务中对多个数据同时进行操作。两者可以同时存在,提高整体的并行性。
-
Amdahl’s Law: Amdahl’s Law 描述了在一个程序中只有一部分可以并行执行时,整体性能的上限。它强调了优化串行部分对提高整体性能的重要性。
并行执行在高性能计算、大规模数据处理、图形处理等领域有着广泛的应用。然而,并行编程也面临一些挑战,如数据同步、通信开销、负载均衡等问题。在设计并行系统时,需要综合考虑这些因素,以实现高效的并行执行。
五、进程、线程和并行执行
进程、线程
现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统。
进程: 就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。
线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位。
进程就好比一家公司,是操作系统对程序进行运行管理的单位
线程就好比公司的员工,进程可以有多个线程(员工),是进程实际的工作者
操作系统中可以运行多个进程,即多任务运行
一个进程内可以运行多个线程,即多线程运行
注意点:
进程之间是内存隔离的, 即不同的进程拥有各自的内存空间。 这就类似于不同的公司拥有不同的办公场所。
线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。
这就好比,公司员工之间是共享公司的办公场所。
并行执行
并行执行的意思指的是同一时间做不同的工作。
进程之间就是并行执行的,操作系统可以同时运行好多程序,这些程序都是在并行执行。
除了进程外,线程其实也是可以并行执行的。
也就是比如一个Python程序,其实是完全可以做到:
- 一个线程在输出:你好
- 一个线程在输出:Hello
像这样一个程序在同一时间做两件乃至多件不同的事情, 我们就称之为:多线程并行执行
总结
- 什么是进程
程序在操作系统内运行,即成为一个运行进程 - 什么是线程
进程内部可以有多个线程,程序的运行本质上就是由进程内部的线程在实际工作的。 - 什么是并行执行
- 多个进程同时在运行,即不同的程序同时运行,称之为:多任务并行执行
- 一个进程内的多个线程同时在运行,称之为:多线程并行执行
六、多线程编程
使用threading模块完成多线程编程
threading模块
""""
多线程运行模式
"""
sing_thread =threading.Thread(target=sing)
dance_thread =threading.Thread(target=dance)
sing_thread.start()
dance_thread.start()
代码
"""
演示多线程编程的使用
"""
import time
import threading
def sing(msg):
print(msg)
time.sleep(1)
def dance(msg):
print(msg)
time.sleep(1)
if __name__ == '__main__':
# 创建一个唱歌的线程
sing_thread = threading.Thread(target=sing, args=("我要唱歌 哈哈哈", ))
# 创建一个跳舞的线程
dance_thread = threading.Thread(target=dance, kwargs={"msg": "我在跳舞哦 啦啦啦"})
# 让线程去干活吧
sing_thread.start()
dance_thread.start()
总结
- threading模块的使用
thread_obj = threading.Thread(target=func)
创建线程对象
thread_obj.start()
启动线程执行
import threading
thread_obj = threading.Thread([group [, target [, name [, args [, kwargs]]]]])
-group:暂时无用,未来功能的预留参数
-target:执行的目标任务名
-args:以元组的方式给执行任务传参
-kwargs:以字典方式给执行任务传参
-name:线程名,一般不用设置
# 启动线程
thread_obj.start()
- 如何传参
需要传参的话可以通过:args
参数通过元组(按参数顺序)的方式传参- 或使用
kwargs
参数用字典的形式传参