8.7 python 日学 线程进阶、协程

1.同步
例如8.6上一篇博客最后的那个问题,之所以会出现那样的情况原因就是,没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程的结果不可预期,这样的现象称为‘线程不安全’

解决思路:利用同步来进行解决

from threading import Thread,Lock

import time

g=0

def hs1():

global g

l.acquire()

for i in range(100000):

g+=1

print(‘hs1’,g)

l.release()

def hs2():

global g

l.acquire()

for i in range(100000):

g+=1

print(‘hs2’,g)

l.release()

if name == ‘main’:

l=Lock()

h1=Thread(target=hs1)

h2=Thread(target=hs2)

h1.start()

h2.start()

线程执行函数1时,对其加锁,使得函数2的请求加锁的请求被阻碍,只有函数1完全执行完毕,释放锁后,线程2才能得到锁,继续执行下去。

2.异步
同步调用就是你喊朋友去吃饭,朋友在忙,你就一直等,等你朋友忙完,你们再一起去吃饭
异步调用就是你喊朋友去吃饭,朋友在忙说忙完找你,你就去做别的事了。

from multiprocessing import Pool

import time

def zuoye(name):

print(name,‘在写代码’)

time.sleep(1)

return name+‘写完代码了’

def chouyan(status):

print(‘去抽烟因为’+status)

if name == ‘main’:

p=Pool(1)

p.apply_async(zuoye,(‘张三’,),callback=chouyan)

p.close()

p.join()

3.互斥锁
当多个线程几乎同时修改一个共享数据时,需要进行同步控制,线程同步能够保证多个线程安全的访问竞争资源,最简单的机制就是使用互斥锁
当一个线程调用锁的acquire()方法获得锁时,锁就进入locked状态,每次只有一个线程可以得到锁,,如果此时另一个线程试图获得锁,那么该线程就会变为blocked状态,直到拥有锁的线程release()

好处:
确保了某段关键代码只能由一个线程从头到尾完整的执行
坏处:
阻止了多线程的并发执行,效率下降。由于可能存在多个锁,因此可能会造成死锁。

4.死锁
如果两个线程分别占有一部分资源,并同时等待对方发资源,就会造成死锁现象。

from threading import Thread,Lock

import time

g=0

def hs1():

global g

for i in range(100000):

l1.acquire()

print(‘函数1锁1得到锁,请求锁2’)

time.sleep(1)

l2.acquire()

print(‘1111111111111111111111’)

g+=1

l2.release()

l1.release()

print(‘hs1’,g)

def hs2():

global g

for i in range(100000):

l2.acquire()

print(‘函数2锁2得到锁,请求锁1’)

time.sleep(1)

l1.acquire()

print(‘22222222222222222222222’)

l1.release()

l2.release()

g+=1

print(‘hs2’,g)

if name == ‘main’:

l1=Lock()

l2=Lock()

h1=Thread(target=hs1)

h2=Thread(target=hs2)

h1.start()

h2.start()

5.队列

import queue

q=queue.Queue(3)

q.put(1)

q.put(2)

q.put(3)

# print(‘1111111’,q.full())

# q.put(4)

while q.qsize()>0:

print(q.get())

print(‘end’)

队列优先级

import queue

q=queue.PriorityQueue(5)

q.put((1,‘a’))

q.put((5,‘xj’))

q.put((2,‘xg’))

q.put((-9,‘mg’))

while q.qsize()>0:

print(q.get())

队列后入先出

import queue

q=queue.LifoQueue(4)

q.put(1)

q.put(2)

q.put(3)

q.put(4)

while q.qsize()>0:

print(q.get())

6.threadlocal
在多线程环境下,每个线程都有自己的数据,一个线程使用自己的局部变量比使用全局变量要好,因为局部变量只有自己能看见,不会影响其他线程,而全局变量的修改必须加锁

from threading import Thread

import time,threading

local=threading.local()

def hanshu1(name):

local.name=name

# for i in range(100000):

# pass

hanshu2()

def hanshu2():

print(threading.current_thread(),local.name)

if name == ‘main’:

t1=Thread(target=hanshu1,args=(‘张三’,),name=‘线程帅哥’)

t2=Thread(target=hanshu1,args=(‘李四’,),name=‘线程美女’)

t1.start()

t2.start()

7.协程
协程是比线程更小的执行单元,协程自带上下文,只要在合适的时机,我们可以吧一个协程切换到另一个协程。通俗的理解:在一个线程中某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后在切换到另一个函数中执行,注意,这不是通过函数调用做到的,切换的次数和时机都是由开发者决定的。

这个过程看起来和线程差不多,但其实不然,线程切换从系统层面远不止保存和恢复cpu上下文那么简单,线程切换非常耗性能,但协程的切换只是单纯操作cpu上下文。

def hanshu():

a=3

for x in range(10):

yield x+a

a+=1

x=hanshu()

for y in x:

print(y)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值