有了GIL还是会出现数据不安全,所以还是要用锁
import time
from threading import Thread,Lock
n = 100
def func(lock):
global n
with lock:
tmp = n-1
n = tmp
l = []
lock = Lock()
for i in range(100):
t = Thread(target = func,args = (lock,))
t.smxtart()
l.append(t)
for t in l:t.join()
print(n)
dis模块(判断数据是否安全)
import dis
n = 1
def func():
n = 100
n -= 1
dis.dis(func)
死锁现象
死锁不是时刻发生的,有偶然的情况,每一个线程中不止一把锁,并且套着使用
解决死锁的方案
如果某一件事情需要两个资源同时出现,那么不应该将两个资源通过两把锁控制,而是看做是一个资源,用一把锁控制,先临时解决,然后找到死锁原因,再去修改(科学家吃面条)(递归锁也能解决死锁现象)。
出现死锁现象
# def eat1(name):
# noodle_lock.acquire()
# print('%s拿到面条了'%name)
# fork_lock.acquire()
# print('%s拿到叉子了'%name)
# print('%s开始吃面'%name)
# time.sleep(0.2)
# fork_lock.release()
# print('%s放下叉子了' % name)
# noodle_lock.release()
# print('%s放下面了' % name)
#
# def eat2(name):
# fork_lock.acquire()
# print('%s拿到叉子了' % name)
# noodle_lock.acquire()
# print('%s拿到面条了' % name)
# print('%s开始吃面' % name)
# time.sleep(0.2)
# noodle_lock.release()
# print('%s放下面了' % name)
# fork_lock.release()
# print('%s放下叉子了' % name)
#
# Thread(target=eat1,args=('alex',)).start()
# Thread(target=eat2,args=('wusir',)).start()
# Thread(target=eat1,args=('太白',)).start()
# Thread(target=eat2,args=('宝元',)).start()
解决死锁
# lock = Lock()
# def eat1(name):
# lock.acquire()
# print('%s拿到面条了'%name)
# print('%s拿到叉子了'%name)
# print('%s开始吃面'%name)
# time.sleep(0.2)
# lock.release()
# print('%s放下叉子了' % name)
# print('%s放下面了' % name)
#
# def eat2(name):
# lock.acquire()
# print('%s拿到叉子了' % name)
# print('%s拿到面条了' % name)
# print('%s开始吃面' % name)
# time.sleep(0.2)
# lock.release()
# print('%s放下面了' % name)
# print('%s放下叉子了' % name)
#
# Thread(target=eat1,args=('alex',)).start()
# Thread(target=eat2,args=('wusir',)).start()
# Thread(target=eat1,args=('太白',)).start()
# Thread(target=eat2,args=('宝元',)).start()
递归锁(RLock)
在同一个线程中可以无限次acquire,但是要想在其他线程中也acquire,必须先在自己线程中添加和acquire次数相同的release
import time
noodle_lock = fork_lock = RLock()
def eat1(name):
noodle_lock.acquire()
print('%s拿到了面条'%name)
frok_lock.aquire()
print('%s拿到了叉子'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
fork_lock.release()
print('%s放下叉子'%name)
noodle_lock.release()
print('%s放下面条'%name)
def eat2(name):
fork_lock.acquire()
print('%s拿到了叉子'%name)
noodle_lock.acquire()
print('%s拿到了面条'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
fork_lock.release()
print('%s放下叉子'%name)
noodle_lock.release()
print('%s放下面条'%name)
Thread(target = eat1,args = ('alex',)).start()
Thread(target = eat1,args = ('wusir',)).start()
Thread(target = eat1,args = ('taibai',)).start()
Thread(target = eat1,args = ('baiyuan',)).start()
线程 信号量(Semaphore)
import time
from threading import Semaphore,Thread
def func(name,sem):
sem.acquire()
print(name,'start')
time.sleep(1)
print(name,'stop')
sem.release()
sem = Semaphore(5)
for i in range(20):
Thread(target=func,args=(i,sem)).start()
进程池
有1000个任务,一个进程池中有5个进程,所有的1000个任务会多次利用这五个进程来完成任务
信号量
有1000个任务,有1000个线程、进程所有的1000个任务由于信号量的控制,只能5个5个的执行
线程事件 (Event)
wait()阻塞 事件内部标识为True就停止阻塞
控制标识
set #True
clear #False
is_set #判断是不是True
连接数据库(用事件)
import time
import random
from threading import Thread,Event
def connect_sql(e):
count = 0
while count < 3:
e.wait(0.5)
if e.is_set():
print('连接数据库成功')
break
else:
print('数据库未连接成功')
count += 1
F
def test(e):
time.sleep(random.randint(0,3))
e.set()
e = Event()
Thread(target=test,args=(e,)).start()
Thread(target=connect_sql,args=(e,)).start()
线程条件()
wait 阻塞
notify(n) 给信号
假如现在有20个线程,所有的线程都在wait这里阻塞,nptify(n)n传了多少,那么wait这边就能收获得到多少个解除阻塞的通知
import threading
def run(n):
con.acquire()
con.wait()
print("run the thread: %s" % n)
con.release()
if __name__ == '__main__':
con = threading.Condition()
for i in range(10):
t = threading.Thread(target=run, args=(i,))
t.start()
while True:
inp = input('>>>')
if inp == 'q':
break
con.acquire()
con.notify(int(inp))
con.release()
print('****')
设置某个条件
如果满足这个条件 就可以释放线程
监控测试我的网速
20000个任务
测试我的网速 /系统资源
发现系统资源有空闲,我就放行一部分任务
线程定时器(Timer)
from threading import Timer
def func():
print('执行我啦')
t = Timer(3,func) #参数3为3秒,就是等待3秒在执行子线程
# 现在这个时间点我不想让它执行,而是预估一下大概多久之后它执行比较合适
t.start()
print('主线程的逻辑')
线程队列(Queue) #先进先出
q = queue.Queue()
线程栈(LifoQueue) #先进后出
lfq = queue.LifoQueue() # 栈
lfq.put(1)
lfq.put(2)
lfq.put(3)
print(lfq.get())
print(lfq.get())
print(lfq.get())
优先级队列(PriorityQueue) #根据第一个值的大小来排定优先级(ascii码越小,优先级越高)
q = queue.PriorityQueue()
q.put((2,'a'))
q.put((1,'c'))
q.put((1,'b'))
print(q.get())
线程池
concurrent.futures