GIL http://www.cnblogs.com/tkqasn/p/5701230.html

cpython解释器 GIL全局解释器锁 global interpret lock

threading模块

线程

轻量级进程,是CPU对资源进行调度的最小单位。
可见创建一个线程比创建一个进程所消耗的资源更少。

创建线程 Thread(target=,arg=() ...)

线程之间共享全局资源,在同一个进程内部都可以访问到。但是如果同一个进程内部都想要修改一个数据的时候,此时就会产生 数据竞争 的现象,从而导致数据错乱。

互斥锁 Lock()

上厕所需要加锁,不然就会产生误会。

mutex  = threading.Lock()
  • 获取锁

    lock the lock, possibly blocking until it can be obtained 阻塞等待直到获取到锁资源

    mutex.acquire()

注意: 即使是同一线程也不允许连续多次获取同一个互斥锁(导致死锁)。


#coding=utf-8

import  threading
import  time

def t0(lock):
    lock.acquire()
    print ("acquire1 done")

    lock.acquire()
    print ("acquire1 done")

    lock.release()
    print ("release1 done")

    lock.release()
    print ("release2 done")

if __name__ == '__main__':
    mtx = threading.Lock()
    tt0 = threading.Thread(target=t0,args=(mtx,))
    tt0.start()

    time.sleep(2)
    print("state : ", mtx.locked())

# 运行结果
# python client.py
#     acquire1 done
#     ('state : ', True)
  • acquire()函数参数说明

acquire(blocking=True, timeout=-1) -> bool

Lock the lock. Without argument, this blocks if the lock is already locked (even by the same thread), waiting for another thread to release the lock, and return True once the lock is acquired.

With an argument, this will only block if the argument is true, and the return value reflects whether the lock is acquired. The blocking operation is interruptible.

blocking参数表示是否要阻塞等待拿到锁

timeout参数表示阻塞等待的超时时间(interruptible可中断意义在这里)

  • 释放锁

    unlock of the lock

    mutex.release()

注意: 要求锁必须在locked状态,但是执行release()操作并不需要和执行acquire()操作在同一线程

#coding=utf-8

import  threading
import  time

def t0(lock):
    lock.acquire()
    print ("acquire1 done")

def t1(lock):
    print ("release done")
    time.sleep(1)
    #lock.release()

if __name__ == '__main__':
    mtx = threading.Lock()
    tt0 = threading.Thread(target=t0,args=(mtx,))
    tt1 = threading.Thread(target=t1, args=(mtx,))
    tt0.start()
    tt1.start()

    time.sleep(2)
    print("state : ", mtx.locked())    # False
  • 测试锁状态

    test whether the lock is currently locked

    mutext.locked()

    True表示被锁定 False表示未被锁定

  • 临界区

  • 注意点

    获取锁、释放锁本身对系统资源有一定的消耗 临界区越小,锁粒度越小对系统资源消耗越少。

可重入锁 RLock()

RLock允许在同一线程中被多次acquire,acquire和release次数需要相等。


#coding=utf-8

import  threading
import  time

def t0(lock):
    lock.acquire()
    print ("acquire1 done")

    lock.acquire()
    print ("acquire1 done")

    lock.release()
    print ("release1 done")

    lock.release()
    print ("release2 done")

if __name__ == '__main__':
    lk = threading.RLock()
    tt0 = threading.Thread(target=t0,args=(lk,))
    tt0.start()

    time.sleep(2)
    #print("state : ", lk.locked())    #可重入锁没有locked函数成员

    # 运行结果
    # acquire1 done
    # acquire1 done
    # release1 done
    # release2 done

条件变量

threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

Condition.wait([timeout]):
  wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。 Condition.notify():   唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。 Condition.notify_all() Condition.notifyAll()   唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

notify(n=1)                  唤醒最大n个等待的线程
notifyAll()、notify_all()    唤醒所有等待的线程

信号量

Semaphore(信号量)是计算机科学史上最古老的同步指令之一。Semaphore管理一个内置的计数器,每当调用acquire()时-1,调用release() 时+1。计数器不能小于0;当计数器为0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。

Event

Event(事件)是最简单的线程通信机制之一:一个线程通知事件,其他线程等待事件,Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态,源代码中调用了norifyall

Queue队列

Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。内部实现使用了mutex和condition

results matching ""

    No results matching ""