#!/usr/bin/env python
-- coding:utf-8 --
线程中是不是会产生数据不安全
# 共享内存
a = 0
def add_f():
global a
for i in range(200000):
a += 1
def sub_f():
global a
for i in range(200000):
a -= 1
from threading import Thread
t1 = Thread(target=add_f)
t1.start()
t2 = Thread(target=sub_f)
t2.start()
t1.join()
t2.join()
print(a)
a = 0
def func():
global a
a -= 1
import dis
dis.dis(func)
即便是线程 即便有GIL 也会出现数据不安全的问题
# 1.操作的是全局变量
# 2.做一下操作
# += -= *= /+ 先计算再赋值才容易出现数据不安全的问题
# 包括 lst[0] += 1 dic['key']-=1
a = 0
def func():
global a
a += 1
import dis
dis.dis(func)
a = 0
def add_f(lock):
global a
for i in range(200000):
with lock:
a += 1
def sub_f(lock):
global a
for i in range(200000):
with lock:
a -= 1
from threading import Thread,Lock
lock = Lock()
t1 = Thread(target=add_f,args=(lock,))
t1.start()
t2 = Thread(target=sub_f,args=(lock,))
t2.start()
t1.join()
t2.join()
print(a)
加锁会影响程序的执行效率,但是保证了数据的安全
互斥锁是锁中的一种:在同一个线程中,不能连续acquire多次
from threading import Lock
lock = Lock()
lock.acquire()
print(’*’*20)
lock.release()
lock.acquire()
print(’-’*20)
lock.release()
单列模式
#!/usr/bin/env python
-- coding:utf-8 --
import time
from threading import Lock
class A:
__instance = None
lock = Lock()
def new(cls, *args, **kwargs):
with cls.lock:
if not cls.__instance:
time.sleep(0.1)
cls.__instance = super().new(cls)
return cls.__instance
def init(self,name,age):
self.name = name
self.age = age
def func():
a = A(‘alex’, 84)
print(a)
from threading import Thread
for i in range(10):
t = Thread(target=func)
t.start()
#!/usr/bin/env python
-- coding:utf-8 --
import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name,noodle_lock,fork_lock):
noodle_lock.acquire()
print(’%s抢到面了’%name)
fork_lock.acquire()
print(’%s抢到叉子了’ % name)
print(’%s吃了一口面’%name)
time.sleep(0.1)
fork_lock.release()
print(’%s放下叉子了’ % name)
noodle_lock.release()
print(’%s放下面了’ % name)
def eat2(name,noodle_lock,fork_lock):
fork_lock.acquire()
print(’%s抢到叉子了’ % name)
noodle_lock.acquire()
print(’%s抢到面了’%name)
print(’%s吃了一口面’%name)
time.sleep(0.1)
noodle_lock.release()
print(’%s放下面了’ % name)
fork_lock.release()
print(’%s放下叉子了’ % name)
lst = [‘alex’,‘wusir’,‘taibai’,‘yuan’]
Thread(target=eat1,args=(lst[0],noodle_lock,fork_lock)).start()
Thread(target=eat2,args=(lst[1],noodle_lock,fork_lock)).start()
Thread(target=eat1,args=(lst[2],noodle_lock,fork_lock)).start()
Thread(target=eat2,args=(lst[3],noodle_lock,fork_lock)).start()
锁
# 互斥锁
# 在一个线程中连续多次acquire会死锁
# 递归锁
# 在一个线程中连续多次acquire不会死锁
# 死锁现象
# 死锁现象是怎么发生的?
# 1.有多把锁,一把以上
# 2.多把锁交替使用
# 怎么解决
# 递归锁 —— 将多把互斥锁变成了一把递归锁
# 快速解决问题
# 效率差
# ***递归锁也会发生死锁现象,多把锁交替使用的时候
# 优化代码逻辑
# 可以使用互斥锁 解决问题
# 效率相对好
# 解决问题的效率相对低
#!/usr/bin/env python
-- coding:utf-8 --
from threading import RLock
rlock = RLock()
rlock.acquire()
print(’*’*20)
rlock.acquire()
print(’-’*20)
rlock.acquire()
print(’*’*20)
在同一个线程中,可以连续acuqire多次不会被锁住
递归锁:
# 好 :在同一个进程中多次acquire也不会发生阻塞
# 不好 :占用了更多资源
import time
from threading import RLock,Thread
noodle_lock = RLock()
fork_lock = RLock()
noodle_lock = fork_lock = RLock()
print(noodle_lock,fork_lock)
def eat1(name,noodle_lock,fork_lock):
noodle_lock.acquire()
print(’%s抢到面了’%name)
fork_lock.acquire()
print(’%s抢到叉子了’ % name)
print(’%s吃了一口面’%name)
time.sleep(0.1)
fork_lock.release()
print(’%s放下叉子了’ % name)
noodle_lock.release()
print(’%s放下面了’ % name)
def eat2(name,noodle_lock,fork_lock):
fork_lock.acquire()
print(’%s抢到叉子了’ % name)
noodle_lock.acquire()
print(’%s抢到面了’%name)
print(’%s吃了一口面’%name)
time.sleep(0.1)
noodle_lock.release()
print(’%s放下面了’ % name)
fork_lock.release()
print(’%s放下叉子了’ % name)
lst = [‘alex’,‘wusir’,‘taibai’,‘yuan’]
Thread(target=eat1,args=(lst[0],noodle_lock,fork_lock)).start()
Thread(target=eat2,args=(lst[1],noodle_lock,fork_lock)).start()
Thread(target=eat1,args=(lst[2],noodle_lock,fork_lock)).start()
Thread(target=eat2,args=(lst[3],noodle_lock,fork_lock)).start()
#!/usr/bin/env python
-- coding:utf-8 --
import time
from threading import Lock,Thread
lock = Lock()
def eat1(name,noodle_lock,fork_lock):
lock.acquire()
print(’%s抢到面了’%name)
print(’%s抢到叉子了’ % name)
print(’%s吃了一口面’%name)
time.sleep(0.1)
print(’%s放下叉子了’ % name)
print(’%s放下面了’ % name)
lock.release()
def eat2(name,noodle_lock,fork_lock):
lock.acquire()
print(’%s抢到叉子了’ % name)
print(’%s抢到面了’%name)
print(’%s吃了一口面’%name)
time.sleep(0.1)
print(’%s放下面了’ % name)
print(’%s放下叉子了’ % name)
lock.release()
lst = [‘alex’,‘wusir’,‘taibai’,‘yuan’]
Thread(target=eat1,args=(lst[0],noodle_lock,fork_lock)).start()
Thread(target=eat2,args=(lst[1],noodle_lock,fork_lock)).start()
Thread(target=eat1,args=(lst[2],noodle_lock,fork_lock)).start()
Thread(target=eat2,args=(lst[3],noodle_lock,fork_lock)).start()
#!/usr/bin/env python
-- coding:utf-8 --
import queue
线程之间的通信 线程安全
from queue import Queue # 先进先出队列
q = Queue(5)
q.put(0)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
print(‘444444’)
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
使用多线程 实现一个请求网页 并且把网页写到文件中
生产者消费者模型来完成
5个线程负责请求网页 把结果放在队列里
2个线程 负责从队列中获取网页代码 写入文件
from queue import LifoQueue # 后进先出队列
last in first out 栈
lfq = LifoQueue(4)
lfq.put(1)
lfq.put(3)
lfq.put(2)
print(lfq.get())
print(lfq.get())
print(lfq.get())
先进先出
# 写一个server,所有的用户的请求放在队列里
# 先来先服务的思想
后进先出
# 算法
优先级队列
# 自动的排序
# 抢票的用户级别 100000 100001
# 告警级别