python多线程
基本概念
线程和进程
进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统资源分配和调度的基本单位,是操作系统的基本单位。
线程:有时被称为轻量级进程,是程序执行流的最小单元。一个标准的线程由线程ID,当前指针(pc),寄存器集合和堆栈组成。
并发解决模型
以下以火车站进站模型为例
1.队列,缓冲区
例子:火车站的乘客排队进站,排成的队就是一个缓冲区。军人,老幼病残优先,所以也有优先队列。
(queue模块的类queue,redis等)
2.争抢模式
谁抢到算谁的。同一时间只能进去一人,一个人进去,其余人不能进,等他进去后才能再进。
(锁机制:文件锁和线程锁)
3.预处理模式
在高峰时期多开几个通道,维持秩序。
(一种提前加载用户需求的数据思路,预处理思想,缓存常用)
4.并行模式
进站分为不同的进站口,每个进站口分为不同的队列,加速进站。
(可以通过购买服务器,多开进程,线程实现并行处理解决并发问题,水平扩展,分布式思想)
5.提速
多通道无法满足现阶段需求,进站不是问题,问题是如何传运如此多的人,把绿皮火车换为高铁,提高自身硬件条件。
(通过更新cpu,内存,硬盘等资源)
6.消息中间件
在进站前增加安检,在安检时就进行排队
(计算机中常见的消息中间件RabbitMQ,ActiveMQ(Apache),PocketMQ(Ali),Kafka(Apache)等)
线程生命周期
就绪:线程能够运行,但是在等待被调用,可能线程刚刚创建启动,或者刚刚从阻塞中恢复,或者被其他线程抢占。
运行:线程正在运行。
阻塞:线程等待外部时间发生而且无法运行,如I/O操作。
终止:线程完成,或推迟,或被取消。
Thead类
签名
def init(self,group=None,target=None,name=None,args=(),kwargs=None,deamon=None)
target:线程的对象,就是目标函数
name:为线程起名字
args:为目标函数传递实参,元组
kwargs:为目标函数关键字传参,字典
Thead 线程和主线程的关系
守护线程
如果不设置deamon,就取当前线程的deamon来设置它。
主线程为non-deamon线程,即deamon=False
从主线程创建的所有线程不设置deamon属性,则默认都是deamon=False,也就是None=deammon线程。
线程中只要有:None=deamon线程时就无法退出。
线程属性
模块属性
线程属性
以小红车小蓝车过红绿灯为例
import time
import threading
llight = {}
def linght(sconds):
count = 5
llight[threading.current_thread().name]="ret"
while True:
name = threading.current_thread().name
print("{} is {} now!,senconds is {}".format(name,llight[threading.current_thread().name],count))
count -= 1
if count == 0 and llight[threading.current_thread().name] == "ret":
llight[threading.current_thread().name] = "blue"
count = 5
if count == 0 and llight[threading.current_thread().name] == "blue":
llight[threading.current_thread().name] = "ret"
count = 5
time.sleep(sconds)
def car(s):
for k,v in llight.items():
if v == "ret":
count = 0
while True:
time.sleep(0.5)
count += 0.5
if llight[k] != "ret":
print("ret to blue,car pass")
break
if count > s:
print("ret ret go go go!")
break
else:
print("blue light pass".format(k))
lt = threading.Thread(target=linght,args=(2,),name="light1").start()
lt1 = threading.Thread(target=linght,args=(4,),name="light2").start()
ct = threading.Thread(target=car,args=(6,)).start()
线程同步
线程同步Event
Event事件,是线程间通信机制中最简单的实现,使用一个内部标记flag,通过flag的true或false的变化进行操作。
event = threading.Event()
print(“ready”)
print(event.wait(4))#默认false,执行wait时长为4s,函数返回值
print(“done”)
线程同步Lock,Rlock
锁,凡是存在共享资源争抢的地方都可以使用锁,从而保证只有一个使用者可以完成使用一个资源。
Lock:锁,一旦线程获得锁,其他线程试图获取锁的线程将被阻塞
可重复锁rlock,在一个线程中,可以锁多次,锁多次时,就要对于的解锁多次,否则其他阻塞锁中,无法执行任务
线程不同:condition
构造方法Condition(lock=None),可以传入一个lock或Rlock对象,默认是Rlock
Conddition用于生产者、消费者模型,为了解决生产者和消费者速度不匹配的问题。
使用方式:
使用Condition,必须先acquire,用完了要release,因为内部使用了锁,默认使用了Rlock锁,最好使用方式是with上下文。
消费者wait,等待通知。
生产者生产好消息,对消费者发通知,可以使用notify或者notify_all方法
通知案例:
cond = threading.Condition()
env = threading.Event()
data = 0
def produce(total):
for _ in range(total):
global data
data = random.randint(0,100)
with cond:
print(data)
cond.notify_notify(n=2)
env.wait(1)
env.set()
def consume():
global data
while not env.is_set():
with cond:
cond.wait() #阻塞等通知
print("received {}".format(data))
data = None
env.wait(0.5)
p = threading.Thread(target=produce,args=(10,),name="producer")
for con in range(5):
con = threading.Thread(target=consume,name=“consumer”) #5个消费者,等待处理,现在最多通知5个,一对多广播
con.start()
p.start()
进程池
multiprocess.Pool是进程池类
import multiprocessing
import datetime
start = datetime.datetime.now()
def calc(i):
sum = 0
for _ in range(1000000000):
sum += 1
print(i,sum)
return sum
A = []
if __name__ == "__main__":
start = datetime.datetime.now()
pool = multiprocessing.Pool(5)
for i in range(5):
#回调函数必须接受一个参数
pool.apply_async(calc,args=(i,),callback=lambda x:A.extend(x))
pool.close()
pool.join()
delta = (datetime.datetime.now() -start).total_seconds()
print(delta)
print(A)