ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

day30

2019-10-23 19:00:51  阅读:263  来源: 互联网

标签:name lock acquire day30 release 线程 print


目录

GIL全局解释器

GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

要想了解GIL,首先确定一点:每次执行python程序,都会产生一个独立的进程。例如python test.py,python aaa.py,python bbb.py会产生不同的python进程

基于Cpython来研究全局解释锁

​ 1.GIL本质上是一个互斥锁

​ 2.GIL是为了阻止同一个进程内多个线程同时执行(并行)

​ 单个进程下的多个线程无法实现并行,但能实现并发

​ 3.这把锁主要是因为CPython的内存管理不是“线程安全”的

​ 内存管理

​ 垃圾回收机制

​ GIL的存放就是为了保证线程安全的

​ 注意:多线程过来执行,一旦遇到IO操作,就会立马释放GIL解释器,交给下一个先进来的进程

import time
from threading import Thread,current_thread
number = 100
def task():
    global number
    number2 = number
    number = number2 - 1
    print(number,current_thread().name)
for line in range(100):
    t = Thread(target=task)
    t.start()

验证多线程的作用

多线程的作用:

​ 站在两个角度去看问题:

​ 四个任务,计算密集型,每个任务需要10s

​ 单核:

​ 开启进程

​ 4个进程:40s

​ 开启线程

​ 消耗资源远小于进程

​ 4个线程:40s

​ 多核:

​ 开启进程

​ 并行执行,效率比较高

​ 4个进程:10s

​ 开启线程

​ 并发执行,执行效率低

​ 4个线程:40s

​ 四个任务,IO密集型,每个任务需要10s

​ 单核:

​ 开启进程

​ 消耗资源过大

​ 4个进程:40s

​ 开启线程

​ 消耗资源远小于进程

​ 4个线程:40s

​ 多核:

​ 开启进程
​ 并行执行,效率小于多线程,因为遇到IO立马切换CPU的执行权限

​ 4个进程:40s+开启进程消耗的额外时间

​ 4个线程:40s

在计算密集的情况下:

​ 使用多进程

在IO密集型的情况下:

​ 使用多线程

高效执行多进程内多个IO密集型的程序:

​ 使用 多进程+多线程

应用:

​ 多线程用于IO密集型,如socket,爬虫,web

​ 多进程用于计算密度型,如金融分析

死锁现象

​ 所谓死锁:指的是两个或两个以上的进程或线程在执行过程中,因为夺资源而造成的一种互相等待的现象,若无外力作用,它们都无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永久在互相等待的进程称为死锁进程。

from threading import Lock as Lock
import time
mutexA  = Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

解决死锁的方法:递归,在python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护这一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果用RLock,则不会发生死锁。

典型问题:科学家吃面

死锁问题

#死锁的问题
import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name):
    noodle_lock.acquire()
    print('%s 抢到了面条'%name)
    fork_lock.acquire()
    print('%s 抢到了叉子'%name)
    print('%s 吃面'%name)
    fork_lock.release()
    noodle_lock.release()

def eat2(name):
    fork_lock.acquire()
    print('%s 抢到了叉子' % name)
    time.sleep(1)
    noodle_lock.acquire()
    print('%s 抢到了面条' % name)
    print('%s 吃面' % name)
    noodle_lock.release()
    fork_lock.release()

for name in ['哪吒','nick','tank']:
    t1 = Thread(target=eat1,args=(name,))
    t2 = Thread(target=eat2,args=(name,))
    t1.start()
    t2.start()
递归锁解决死锁问题
import time
from threading import Thread,RLock
fork_lock = noodle_lock = RLock()
def eat1(name):
    noodle_lock.acquire()
    print('%s 抢到了面条'%name)
    fork_lock.acquire()
    print('%s 抢到了叉子'%name)
    print('%s 吃面'%name)
    fork_lock.release()
    noodle_lock.release()

def eat2(name):
    fork_lock.acquire()
    print('%s 抢到了叉子' % name)
    time.sleep(1)
    noodle_lock.acquire()
    print('%s 抢到了面条' % name)
    print('%s 吃面' % name)
    noodle_lock.release()
    fork_lock.release()

for name in ['哪吒','nick','tank']:
    t1 = Thread(target=eat1,args=(name,))
    t2 = Thread(target=eat2,args=(name,))
    t1.start()
    t2.start()

递归锁

递归锁(了解)
用于解决死锁问题
RLock:比喻成万能钥匙,可以提供给多个人去使用
但是第一个使用的时候,会对该锁做一个引用计数
只有引用计数为0时,才能真正释放让另一个去使用

from threading import RLock,Thread,Lock
import time
mutex_a  = mutex_b  = Lock()
class MyThread(Thread):
    #线程执行任务
    def run(self):
        self.func1()
        self.func2()
    def func1(self):
        mutex_a.acquire()
        print(f'用户{self.name}抢到了锁a')
        mutex_b.acquire()
        print(f'用户{self.name}抢到了锁b')
        mutex_b.release()
        print(f'用户{self.name}释放锁b')
        mutex_a.release()
        print(f'用户{self.name}释放锁a')
    def func2(self):
        mutex_b.acquire()
        print(f'用户{self.name}抢到锁b')
        #IO操作
        time.sleep(1)
        mutex_a.acquire()
        print(f'用户{self.name}抢到锁a')
        mutex_a.release()
        print(f'用户{self.name}释放锁a')
        mutex_b.release()
        print(f'用户{self.name}释放锁b')
for line in range(10):
    t= MyThread()
    t.start()

信号量

信号量(了解):
互斥锁:比喻成一个家用马桶

​ 同一时间只能让一个人去使用

信号量:比喻成公厕多个马桶,

​ 同一时间可以让多个人去使用

from threading import Semaphore,Lock
from threading import current_thread
from threading import Thread
import time
sm = Semaphore(5)
mutex = Lock()

def task():
    sm.acquire()
    print(f'{current_thread().name}执行任务')
    time.sleep(1)
    sm.release()
for line in range(20):
    t= Thread(target=task)
    t.start()

线程队列

线程Q(了解级别1):线程队列 面试会问:FIFO

​ FIFO队列:先进先出

​ LIFO队列:后进先出

​ 优先级队列:根据参数内,数字的大小进行分级,数字值越小,优先级越高

import queue
普通的线程队列:先进先出
q = queue.Queue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())  #1

LIFO队列:后进先出
q = queue.LiFoQueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())#3

优先级队列
q=queue.PriorityQueue()
#若参数中传的是元组,会以元组中第一个数字参数为准
q.put(('a优','娃娃头',4))#a==97  ascll码值
q.put(('b优','娃娃头',4))#b==98

1.首先根据第一个参数判断ascll表的数值大小
2.判断第几个参数中的汉字顺序
3.在判断第二个参数中的数字————》字符串数字---》中文
4.以此类推

标签:name,lock,acquire,day30,release,线程,print
来源: https://www.cnblogs.com/gfhh/p/11728104.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有