python生产者消费者写线程池_锁丶threading.local丶线程池丶生产者消费者模型

一丶锁

线程安全:

线程安全能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据,可以由多个线程存取,但是同一时刻只能有一个线程进行存取.

import threading

v = []

def func(arg):

v.append(arg) # 线程安全

print(v)

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

线程安全

1.gil锁

gil锁中文名称为"全局解释器锁",主要体现在多线程中,每个线程在执行的过程中都需要先获取gil,保证同一时刻只有一个线程可以执行代码.而python语言和gil没有半毛钱关系,仅仅是由于历史原因在cpython虚拟机(解释器),难以移除gil

补充:

(线程释放gil锁的情况)在io操作等可能会引起阻塞的system call之前,可以暂时释放gil,但在执行完毕后,必须重新获取gil. python 3.x使用计时器(执行时间达到阈值后,当前线程释放gil)或python 2.x,tickets计数达到100,多线程爬取比单线程性能有所提升,因为遇到io阻塞会自动释放gil锁.

2.lock锁(一次放一个)

import threading

import time

v = []

lock = threading.lock()

def func(arg):

lock.acquire() #加锁

# ++++++++++++++++++被锁的功能

v.append(arg)

time.sleep(0.01)

m = v[-1]

print(arg,m)

#+++++++++++++++++++

lock.release() #解锁

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

# 不加锁: #加锁后

# 2 9 0 0

# 3 9 1 1

# 0 9 2 2

# 1 9 3 3

# 7 9 4 4

# 5 9 5 5

lock

3.rlock锁(一次放一个)

import threading

import time

v = []

lock = threading.rlock()

def func(arg):

lock.acquire()

lock.acquire()

v.append(arg)

time.sleep(0.01)

m = v[-1]

print(arg,m)

lock.release()

lock.release()

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

# 结果:

# 0 0

# 1 1

# 2 2

# 3 3

# 4 4

# 5 5

rlock

lock和rlock 的区别:

lock:lock(指令锁)是可用的最低级别的同步指令.lock处于锁定状态时,不被特定的线程拥有.lock包含两种状态--锁定和非锁定,以及两个基本方法.可以认为lock有一个锁定值池,当线程请求锁定时,将线程至于池中,知道获得锁定后出池.池中的线程处于状态图中的同步阻塞状态.

rlock(可重入锁)是一个可以被同一个线程请求多次的同步指令.rlock使用了"拥有的线程"和"递归等级"的概念,处于锁定状态时,rlock被某个线程拥有.拥有rlock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数.可以认为rlock包含一个锁定池和一个初始值为0的计数器,每次成功调用acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态

简言之: lock属于全局,rlock属于线程

4.boundedsemaphore(一次放指定个数)

import time

import threading

lock = threading.boundedsemaphore(4) #每次允许通过的个数

def func(arg):

lock.acquire() #加锁

print(arg)

time.sleep(2)

lock.release() #解锁

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

boundedsemaphore

5.condition(一次放多个)

import time

import threading

lock = threading.condition()

# ############## 方式一:输入几个取出来几个 ##############

def func(arg):

print('线程进来了')

lock.acquire()

lock.wait() # 加锁

print(arg)

time.sleep(1)

lock.release() #解锁

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

while true:

inp = int(input('>>>'))

lock.acquire()

lock.notify(inp)

lock.release()

#结果:

# 线程进来了

# ....

# 线程进来了

# >>>3

# >>>0

# 1

# 2

# 2

# >>>3

# 4

# 4

# >>>5

# 8

# 6

# 7

# 3

# >>>9

# ############## 方式二(输入一次放一个)##############

#

def xxxx():

print('来执行函数了')

input(">>>")

# ct = threading.current_thread() # 获取当前线程

# ct.getname()

return true

def func(arg):

print('线程进来了')

lock.wait_for(xxxx)

print(arg)

time.sleep(1)

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

#结果

# >> > 线程进来了

# 来执行函数了

# >> > 线程进来了

# 来执行函数了

# >> > 1

# 0

# 2

# 1

# 3

# 2

# 6

condition

6.event(一次放所有)

import threading

lock = threading.event()

def func(arg):

print('线程来了')

lock.wait() # 加锁:红灯

print(arg)

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

input(">>>>")

lock.set() # 绿灯 获取

lock.clear() # 再次变红灯

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

input(">>>>")

lock.set() #绿灯 获取

event

二丶threading.local

作用:内部自动为每一个线程维护一个空间(字典),用于当前存取属于自己的值.保证线程之间的数据隔离

{

线程id: {.....}

线程id: {.....}

线程id: {.....}

}

import time

import threading

data_dict = {}

def func(arg):

ident = threading.get_ident() #获取线程id

data_dict[ident] = arg #{1756: 0, 2636: 1, 8892: 2, 8448: 3, 2344: 4, 7196: 5, 8572: 6, 2268: 7, 2480: 8, 7644: 9}

time.sleep(1)

print(data_dict[ident],arg)

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

import time

import threading

info = {}

class local(object):

def __getattr__(self, item):

ident = threading.get_ident()

return info[ident][item]

def __setattr__(self, key, value):

ident = threading.get_ident()

if ident in info:

info[ident][key] = value

else:

info[ident] = {key:value}

obj = local()

def func(arg):

obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)

time.sleep(2)

print(obj.phone,arg)

for i in range(10):

t =threading.thread(target=func,args=(i,))

t.start()

print(info)#{7688: {'phone': 0}, 8972: {'phone': 1}, 5280: {'phone': 2}, 4724: {'phone': 3},

# 8384: {'phone': 4}, 8680: {'phone': 5}, 8220: {'phone': 6}, 9032: {'phone': 7}, 4660: {'phone': 8},

# 528: {'phone': 9}}

view code

三丶线程池 threadpool模块

可以模拟一个场景,假如我们要去领签名照,在工作室签名的明星只有两个在哪儿,而要领签名照的人很多很多,我们可以创建一个大纸箱子,把那些想要领签名照的人的信息记录下来,然后等明星按顺序来签名.这个大纸箱子就是我们所谓的线程池,存放一个个的需求等待cpu来调度

from concurrent.futures import threadpoolexecutor

import time

def task(a1,a2):

time.sleep(2)

print(a1,a2)

# 创建了一个线程池(最多5个线程)

pool = threadpoolexecutor(5)

for i in range(40):

# 去线程池中申请一个线程,让线程执行task函数。

pool.submit(task,i,8)

import time

import threading

def task(arg):

time.sleep(50)

while true:

num = input('>>>')

t = threading.thread(target=task,args=(num,))

t.start()

线程

import time

from concurrent.futures import threadpoolexecutor

def task(arg):

time.sleep(10)

print("========")

pool = threadpoolexecutor(3)

while true:

num = input('>>>')

pool.submit(task,num)

线程池

四丶生产者消费者模型

所谓生产者消费者模型就是生产者跟消费者的关系而已,就像厨师跟顾客一样,只有厨师做出来饭,顾客才能吃,如果厨师做不出来饭,顾客想吃也吃不到,只能排队等

import time

import queue

import threading

q = queue.queue() # 线程安全

def producer(id):

"""

生产者

:return:

"""

while true:

time.sleep(2)

q.put('包子')

print('厨师%s 生产了一个包子' %id )

for i in range(1,4):

t = threading.thread(target=producer,args=(i,))

t.start()

def consumer(id):

"""

消费者

:return:

"""

while true:

time.sleep(1)

v1 = q.get()

print('顾客 %s 吃了一个包子' % id)

for i in range(1,3):

t = threading.thread(target=consumer,args=(i,))

t.start()

view code

希望与广大网友互动??

点此进行留言吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值