一 . 线程的概念
1. 简介
首先说下,python刚出来的时候,那个时候的计算机都是单核的
简单来说当时一次只能完成一个任务,当有多个任务时候不知道先执行哪个,GIL加了全局解释器锁,这样保证了开启多线程任务时,每次也只能一个任务执行,在执行过程中是随机切换线程任务,约200字节码随机切换!
2. 概念
线程是系统进行资源调度的最小单位,它属于进程,每一个进程中都会有一个线程,由于线程操作是单进程的,所以线程之间可以共享内存变量,互相通信非常方便,它的系统开销比进程小,它是线程之间由于共享内存,会互相影响,如果一个线程僵死会影响其他线程,隔离性和稳定性不如进程,同时,线程并不安全,如果对同一个对象进行操作,需要手动加锁,另外从性能上讲,多线程会触发python的全局解释器锁,导致同一时间点只会有一个线程运行的交替运行模式。
3.使用场景
线程适用于io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务。
4.操作
线程使用的是Threading库 ,往往是先声明线程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定线程数的容器中(list),通过循环或者列表推导式,使用start方法开启线程,join方法阻塞主线程。
import time
import threading
from utils import AuditQueue
import asyncio
def job(num):
# 获取商户uid
uid= asyncio.run(AuditQueue().bout())
if uid:
print(uid)
else:
print("队列为空")
print("任务-{}执行完毕".format(num))
def start_thread(num):
# 创建线程对象
threads = [threading.Thread(target=job, args=(x,)) for x in range(num)]
# 执行多线程任务
for t in threads:
t.start()
for t in threads:
t.join()
if __name__ == '__main__':
start = time.time()
# 审核员数量为3
start_thread(3)
end_time = time.time() - start
print(end_time)
二. 线程相关问题
1.线程锁:
若是使用多线程对整型数据操作,多线程在随机切换的情况下,值是无法恒定的,这时候需要加上一把锁,即线程锁
在多线程的情况下,会出现资源抢占,抢占锁的问题,若不释放锁,会造成死锁问题
# 线程锁
import threading
balance = 0
def change(n):
global balance
if lock.acquire():
try:
for x in range(1000000):
balance = balance + n
balance = balance - n
# 理论上最终一定会执行(出错误也要释放这把锁) exit(-1)打断点就不一定执行 仍然造成死锁
finally:
# 释放锁
lock.release()
if __name__ == '__main__':
threads = [threading.Thread(target=change,args=(x,)) for x in range(6)]
lock = threading.Lock()
[t.start() for t in threads]
[t.join() for t in threads]
print(balance)
2.线程池:
系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互。使用线程池能够存放大量的线程,可以很好的提升性能。
线程池在系统启动时创建大量的空线程,程序只需将一个函数提交给线程池,线程池会启动最后一个线程来执行函数,执行完成,该线程会重新回到线程池中排队,等待新的函数的到来,这样就省去了销毁线程和创建新线程的过程。
线程池还有一点好处就是能够有效的控制系统中并发线程的数量,防止大量并发线程启动,python解释器崩溃
import threading
# 线程池
class Pool:
def __init__(self,num):
self.num = num
# 建立多线程
self.threads = [self.make_connect(x) for x in range(num)]
def make_connect(self,name):
conn = "链接-{}".format(name)
return conn
# 获取链接
def get_connect(self):
return self.threads.pop()
# 归还链接
def return_connect(self,conn):
self.threads.insert(0,conn)