多线程
什么是线程
进程是操作系统调度以及进行资源分配的基础单位,是一个资源单位
线程是操作系统可以运算调度的最小单位,是真正的执行单位,其包含在进程中,一个线程就是一条固定的控制流程。
-
一个进程可以包含多个线程,同一进程中的线程共享进程内的资源
-
特点:系统会为每一个进程自动创建一条线程,称之为主线程,后续通过代码开启的线程称之为子线程(并不是父子关系,只是这么称呼)
进程对比线程
-
进程是一个资源单位,线程是执行单位
-
创建进程的开销远大于线程
-
多个进程之间内存是相互隔离的,而线程是共享进程内的所有资源
-
进程之间是竞争关系,线程是协作关系
-
进程之间有层级关系,而线程之间没有
开启线程也是需要消耗资源的
如果把计算机比喻成一个工厂,那么进程可以看做一个车间,而线程则是流水线
为什么要用线程
- 有多个任务要并发处理
- 当要并发的任务量大的时候,不能使用进程(资源开销大)
CPython的全局锁
使用线程的方法
和使用进程类似,因为本身就是先创造进程,后来发现进程的资源消耗太高,才有的线程,而线程也是继承与进程的
- 方法一:实例化对象
from threading import Thread
def task():
print("bar run")
# 与进程不同之处1 不需要加判断 开启线程的代码放哪里都可以,因为他不会导入这个文件
t = Thread(target=task)
t.start()
print("over")
-
方法二:继承
-
和线程一样,在需要高度自定义的时候使用
from threading import Thread
class MyThread(Thread):
def run(self):
# 把要在子线中执行的代码放入run中
print("bar run")
mt = MyThread()
mt.start()
print("over")
线程安全问题
- 只要你并发的访问了同一个资源,就一定会产生安全问题,线程的解决方案和进程一直,就是给操作公共资源的代码加锁
- 线程间可以访问数据
from threading import Thread,Lock
import time
a = 10
l = Lock()
def task():
global a
l.acquire()
temp = a
time.sleep(0.1)
a = temp - 1
l.release()
ts = []
for i in range(10):
t = Thread(target=task)
t.start()
ts.append(t)
for t in ts:t.join()
print(a)
0
守护线程
概念同进程
默认情况下,主线程即使代码执行完毕,也会等待所有非守护线程完毕后程序才能结束 因为多个线程之间是协作关系 。
from threading import Thread
import time
def task1():
print('t1开始了')
time.sleep(5)
print('t1结束了')
def task2():
print('t2开始了')
time.sleep(3)
print('t2结束了')
print('主开始了哦')
t1 = Thread(target=task1)
t2 = Thread(target=task2)
t1.daemon = True
t1.start()
t2.start()
print('主结束了哦')
主开始了哦
t1开始了
t2开始了
主结束了哦
t2结束了
线程中的常用属性和方法
from threading import Thread,currentThread,enumerate,activeCount
import time
# t = Thread()
# t.start()
# t.join()
# t.is_alive() # 是否存活
# t.isAlive() # 和上面一样,只是写法是小驼峰为了照顾其他程序员
# t.ident # 线程标识符 id
# t.daemon
# 获取当前线程对象
# print(currentThread()) # <_MainThread(MainThread, started 6732)>
# t = Thread(target=lambda :print(currentThread())) # <Thread(Thread-1, started 848)>
# 线程可以用lambda,进程不可以
t = Thread(target=lambda :time.sleep(1))
t.start()
t = Thread(target=lambda :time.sleep(1))
t.start()
# 获取正在运行的所有线程对象 是一个列表
print(enumerate()) # 三个进程的列表,主进程和两个子进程
# 存活的线程数量
print(activeCount()) # 3