目录
在理解进程和线程的概念之前,先了解什么是并行,什么是并发以及并发的解决方案都有哪些?
1. 并行和并发
并行:同一时刻互不干扰的做几件事,例如三个独立的车道分别行驶三辆车
并发:一段时间内处理几件事,例如,多个车辆在某一时段通过同一段路
并发的解决
- 队列、缓冲区:排队一个一个处理,例如排队上车,队伍就是缓冲区
- 争抢:锁机制,谁抢到就上排他锁,其余人只能等待。例如:挤公交,只有一个门可以上,谁抢到谁上,后面的人只能等待,弊端为可能有人长时间抢不到
- 预处理:一种提前加载用户需要的数据的思路,预处理思想,缓存常用。例如,早晚高峰提前调度多辆公交,能够满足现有大部分人的需求
- 并行:日购买更多服务器,或多开进程、线程实现并行处理,来解决并发问题。注意这些都是水平扩展思想。例如:一次性到多辆公交
如果线程在单CPU上处理,就不是并行了。但是多数服务器都是多CPU的,服务的部署往往是多机的、分布式的,这都是并行处理 - 提速:提高单个CPU性能,或单个服务器安装更多的CPU,这是一种垂直扩展思想。例如:将公交核载人数增加
- 消息中间件:常见的消息中间件有RabbitMQ、ActiveMQ (Apache)、RocketMQ( 阿里Apache)、kafka( Apache)等。
2. 进程和线程的概念
进程:
- 一个程序的执行实例就是一个进程,表现为程序是源代码编译后的文件,而这些文件存放在磁盘上。当程序被操作系统加载到内存中,就是进程。
- 进程中存放着指令和数据(资源),它也是线程的容器。
- 进程( Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
- Linux进程有父进程、子进程,Windows的进程是平等关系
线程:
- 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运行单位。
- 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。
- 一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
进程、线程的理解
- 进程间不可以随便的共享数据,同一个进程内的线程可以共享进程的资源,每一个线程拥有自己独立的堆栈
- 在许多系统中,创建一个线程比创建一个进程快10-100倍。
3. 线程的状态
状态 | 含义 |
---|---|
就绪(Ready) | 线程能够运行,但在等待被调度。可能线程刚刚创建启动,或刚刚从阻塞中恢复,或者被其他线程抢占 |
运行(Running) | 线程正在运行 |
阻塞(Blocked) | 线程等待外部事件发生而无法运行,如I/0操作 |
终止(Terminated) | 线程完成,或退出,或被取消 |
线程状态的转换
4. python中的线程开发
进程会启动一个解释器进程,线程共享一个解释器进程
python的线程开发使用标准库threading
Thread类
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
线程的启动和退出
线程启动
start()方法:启动线程。每一个线程必须且只能执行该方法一次
运行时默认创建一个主线程,start()方法可以创建子线程
示例:
import threading
def add(x, y):
print("test thread")
s = x+y
print(s)
print("主线程")
t1 = threading.Thread(target=add,name='add',args=(4,5))
t2 = threading.Thread(target=add,name='add',kwargs={'x':1,'y':2})
t1.start()
t2.start()
Python没有提供线程退出的方法,线程在下面情况时退出
- 线程函数内语句执行完毕
- 线程函数中抛出未处理的异常
threading的属性和方法
名称 | 含义 |
---|---|
current_thread() | 返回当前线程对象 |
main_thread() | 返回主线程对象 |
active_count() | 当前处于alive状态的线程个数 |
enumerate() | 返回所有活着的线程的列表,不包括已经终止的线程和未开始的线程 |
get_ident() | 返回当前线程的ID,非0整数 |
active_count、enumerate方法返回的值还包括主线程
示例:
import threading
import time
def add(x, y):
s = x+y
print(s)
time.sleep(5)
showthread()
print("当前线程名称:",threading.currentThread().name)
def showthread():
print("current_thread:",threading.current_thread())
print("main_thread:", threading.main_thread())
print("active_count:", threading.active_count())
print("thread_id",threading.get_ident())
t1 = threading.Thread(name='add',target=add,args=(4,5))
t1.start()
Thread实例的属性和方法
名称 | 含义 |
---|---|
name | 线程名字,名称可以重名。getName()、setName()获取、设置名称 |
ident | 线程ID,它是非0整数。线程启动后才会有ID,否则为None。 线程退出,此ID依旧可以访问。此ID可以重复使用 |
is_alive() | 返回线程是否活着 |
注:线程的name这是一个名称,可以重复;ID必须唯一,但可以在线程退出后再利用
run方法
运行线程函数,不启动新线程,在主线程中执行
import threading
def add(x, y):
print("test thread")
s = x+y
print(s)
print("主线程")
class MyThread(threading.Thread):
def start(self) -> None:
print("start")
super().start()
def run(self) -> None:
print("run")
super().run()
t1 = MyThread(target=add,name='add',args=(4,5))
t2 = threading.Thread(target=add,name='add',kwargs={'x':1,'y':2})
t1.start()
t2.run()
start()和run() 方法的区别
- start()方法会调用run()方法,而run()方法可以运行函数
- 使用start方法启动线程,启动了一个新的线程。
- 使用run方法,并没有启动新的线程,就是在主线程中调用了一个普通的函数而已。
因此,启动线程请使用start方法,才能启动多个线程。