码迷,mamicode.com
首页 > 编程语言 > 详细

三十六、线程与锁

时间:2018-02-24 21:54:48      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:[]   print   释放   多次   记录   阻塞   func   ima   log   

 

 

创建线程对象的方式:

Thread类直接创建

import threading
import time

def countNum(n): # 定义某个线程要运行的函数

    print("running on number:%s" %n)

    time.sleep(3)

if __name__ == ‘__main__‘:

    t1 = threading.Thread(target=countNum,args=(23,)) #生成一个线程实例
    t2 = threading.Thread(target=countNum,args=(34,))

    t1.start() #启动线程
    t2.start()

    print("ending!")

  

Thread类继承创建

#继承Thread式创建

import threading
import time

class MyThread(threading.Thread):

    def __init__(self,num):
        threading.Thread.__init__(self)  # 用父类的init
        self.num=num

    def run(self):
        print("running on number:%s" %self.num)
        time.sleep(3)

t1=MyThread(56)  # 线程对象
t2=MyThread(78)

t1.start()    # 激活线程对象
t2.start()
print("ending")

  

线程安全

  当多个线程处理公共数据,会出现数据紊乱现象

import threading
import time

def sub():

    global num

    temp=num
    time.sleep(0.1 ) 
   num=temp-1 time.sleep(2) num=100 l=[] lock=threading.Lock() for i in range(100): t=threading.Thread(target=sub,args=()) t.start() l.append(t) for t in l: t.join() print(num)

  

多个线程抢GIL锁,当在sleep状态下的线程,不会去抢GIL锁,其他的线程在抢的时候,之前的不会醒过来,每个线程中都有一个temp=100,当第一个醒来时,进行-1操作,得到99赋值给全局的num,然后再进行sleep,当第二个线程清醒过来,也是用temp=100  减去1,得到99,依次类推,对num赋值99,100次赋值后,结果还是99

如果所有线程执行完之前,有线程清醒,那么就会去抢GIL锁,线程切换之前就把temp赋值操作完成了,所以不进行sleep(0.1)的时候,结果为0

技术分享图片

 

 互斥锁

   全局的一把锁,将代码串行化,保证数据安全

锁通常被用来实现对共享资源的同步访问。为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放),待资源访问完后,再调用release方法释放锁:

import threading

R=threading.Lock()

R.acquire()
‘‘‘
对公共数据的操作
‘‘‘
R.release()

  

 

import threading
import time

def sub():

    global num

    lock.acquire()  #获取锁
    temp=num
    time.sleep(0.001 )
    num=temp-1

    lock.release()  # 释放锁

    #   只能被一个线程占用,后面的线程会等待拿到锁,只有被释放后第二个线程才能继续执行

    time.sleep(2)

num=100

l=[]

lock = threading.Lock() # 互斥锁对象

for i in range(100):
    t=threading.Thread(target=sub,args=())
    t.start()
    l.append(t)

for t in l:
    t.join()

print(num)

  

 死锁:

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

import threading
import time

class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self) # 继承父类

    def run(self):
        self.foo()
        self.bar()
    def foo(self):
        LOCKA.acquire()
        print("%s LOCKA %s"%(self.name,time.ctime()))

        LOCKB.acquire()
        print("%s LOCKB %s"%(self.name,time.ctime()))



        LOCKB.release()
        LOCKA.release()

    def bar(self):
        LOCKB.acquire()
        print("%s LOCKB %s" % (self.name, time.ctime()))

        time.sleep(1)
        # 这里sleep1的时候,A锁已经被其他线程拿到了,这里就拿不到A锁了
        LOCKA.acquire()
        print("%s LOCKA %s" % (self.name, time.ctime()))


        LOCKA.release()
        LOCKB.release()
LOCKA=threading.Lock()
LOCKB=threading.Lock()

for i in range(10):
    t=MyThread()
    t.start()
    
    
# Thread-1 LOCKA Sat Feb 24 15:41:34 2018
# Thread-1 LOCKB Sat Feb 24 15:41:34 2018
# Thread-1 LOCKB Sat Feb 24 15:41:34 2018
# Thread-2 LOCKA Sat Feb 24 15:41:34 2018

  

 递归锁

在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:

 

 原理:

  这把锁允许多次acquire和release,只要计数器大于0,其他线程就没有资格去抢这把锁

 

import threading
import time

class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self) # 继承父类

    def run(self):
        self.foo()
        self.bar()
    def foo(self):
        Rlock.acquire() # 计数1
        print("%s LOCKA %s"%(self.name,time.ctime()))

        Rlock.acquire() # 计数2
        print("%s LOCKB %s"%(self.name,time.ctime()))

        Rlock.release()
        Rlock.release() # 计数 0

    def bar(self):
        Rlock.acquire()
        print("%s LOCKB %s" % (self.name, time.ctime()))

        time.sleep(1)
        # 这里sleep1的时候,A锁已经被其他线程拿到了,这里就拿不到A锁了
        Rlock.acquire()
        print("%s LOCKA %s" % (self.name, time.ctime()))

        Rlock.release()
        Rlock.release()
# LOCKA=threading.Lock()
# LOCKB=threading.Lock()

Rlock = threading.RLock()
for i in range(10):
    t=MyThread()
    t.start()

  

 信号量  Semaphore

 Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()

作用:允许同时开多少个进程

 

import threading
import time

semaphore = threading.Semaphore(5)  # 同时又5个线程,最大连接数5个

def func():
    semaphore.acquire()
    time.sleep(2)
    print("ok")
    semaphore.release()


for i in range(100):
    t=threading.Thread(target=func,args=())
    t.start()

  

 

三十六、线程与锁

标签:[]   print   释放   多次   记录   阻塞   func   ima   log   

原文地址:https://www.cnblogs.com/Mr-chenshuai/p/8467533.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!