python的threading库_python标准库threading源码解读【一】

目录with

condition

semaphore

1. with

还是有必要先讲解一下with的用法。它管理着类的“前世后生”,也就是在进入和退出类的时候调用。当然不是什么类都能够使用“with”:它必须实现两种“特殊方法”,即enter()和exit();字面意思就可以看出来“入口”和“出口”。

基本用法:紧跟with后面的语句被求值后,返回对象的 enter() 方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的 exit()方法。

such as:

而在threading中,with常常和“锁”连用,常用方法如下:

with Lock as lock:

XXX

XXX

print(“END”)

>>> Just Like:

lock = Lock()

lock.acquire() # Notice!

XXX

XXX

print(“END”)

lock.release() # Notice!

我们在下面的源码中会经常看到。

2. condition

condition的本质也是一把“锁”,而且是个“递归锁”。最重要的是,它提供了wait()和notify()方法,而wait()方法就是利用“递归锁”,采用两级锁的方法实现了线程的等待。codition有两级锁,一把一级锁会在进入wait方法的时候释放,离开wait方法的时候再次获取,二级锁会在每次调用wait时分配一个新的锁,并放入condition的等待队列中,而notify负责释放这个锁。如下图:

源码(2-1/3)

class Condition:

def init(self, lock=None):

if lock is None:

lock = RLock()

self.lock = lock

# Export the lock’s acquire() and release() methods

self.acquire = lock.acquire

self.release = lock.release

# If the lock defines releasesave() and/or acquirerestore(),

# these override the default implementations (which just call

# release() and acquire() on the lock). Ditto for isowned().

try:

self.releasesave = lock.releasesave

except AttributeError:

pass

try:

self.acquirerestore = lock.acquirerestore

except AttributeError:

pass

try:

self.isowned = lock.isowned

except AttributeError:

pass

self.waiters = deque()

def enter(self):

return self.lock.enter()

def exit(self, args):

return self.lock._exit(args)

def repr(self):

return “” % (self.lock, len(self.waiters))

def releasesave(self):

self.lock.release() # No state to save

def acquirerestore(self, x):

self.lock.acquire() # Ignore saved state

def isowned(self):

# Return True if lock is owned by current_thread.

# This method is called only if _lock doesn’t have _is_owned().

if self._lock.acquire(0):

self._lock.release()

return False

else:

return True

上述包括:__init__(), __enter__(), __exit__(), __repr__(), _release_save(), _acquire_restore(), _is_owned()。

__enter__(), __exit__():直接继承于Lock的上下文管理方式;

__repr__():特殊方法之一,好像是将condition类用str字符串的方法输出时候,调用此方法

_is_owned():如果一级锁由当前线程获得,返回True。它是怎么判断的呢?

他首先尝试获得一级锁,如果可以获得,那就说明当前线程没有锁,立马释放掉,返回false;反之,返回True;

_release_save(), _acquire_restore():release_save = lock.release(),释放掉一级锁,保存状态

_acquire_restore = lock.acquire(),恢复一级锁

__init__():如果lock为none,则创建一个;

定义lock,即为一级锁;condition类继承locktype的acquire()和release()方法;这些都是非常有用的,且必须的!(废话吗这不是2333333)

如果lock类型定义了_release_save和_acquire_restore尝试重载他们;重载不掉就过,说明lock类型里面就有这种方式,则直接pass;

定义 _waiters 双端队列,注意文件开头的:from collection import deque as _deque.

源码(2-2/3)

def wait(self, timeout=None):

if not self._is_owned():

raise RuntimeError(“cannot wait on un-acquired lock”)

waiter = _allocate_lock()

waiter.acquire()

self._waiters.append(waiter)

saved_state = self._release_save()

gotit = False

try: # restore state no matter what (e.g., KeyboardInterrupt)

if timeout is None:

waiter.acquire()

gotit = True

else:

if timeout > 0:

gotit = waiter.acquire(True, timeout)

else:

gotit = waiter.acquire(False)

return gotit

finally:

self._acquire_restore(saved_state)

if not gotit:

try:

self._waiters.remove(waiter)

except ValueError:

pass

def wait_for(self, predicate, timeout=None):

endtime = None

waittime = timeout

result = predicate()

while not result:

if waittime is not None:

if endtime is None:

endtime = _time() + waittime

else:

waittime = endtime - _time()

if waittime <= 0:

break

self.wait(waittime)

result = predicate()

return result

wait()用于阻塞本线程,直到其他线程调用notify()唤醒或者timeout结束

Line2-3:线程想等待,自己要有锁吧;所以判断当前线程是否有锁,没有就抛出异常;

Line4-6:再定义一个lock方法,变量waiter,并获得这个二级锁(注意,RLock是递归锁,可以嵌套);把这个锁添加进全局私有_waiter 集合最后

Line7:saved_state = self._release_save(),保存状态,释放一级锁;可以让其他线程获得,这样才能调用notify();

Line8:定义一个bool类型的返回值gotit;

Line9-18:直接进入“try”

如果timeout == None,waiter上锁,线程就此阻塞,并且gotit = true ,等待有效;

否则判断timeout的正负性,如果正的,就获得锁线程就此阻塞,返回True赋值给gotit;反之返回False,等待失败;

Line19-25:try……finally……语句通常与资源回收有关

不管try是否含有return,不管try是否抛出异常,finally都会return之前执行。

注意到wait()有可能被用户和系统中断,导致没有上锁的waiter进入了_waiters队列:

finally中首先尝试恢复线程一级锁,也就是等待其他线程释放一级锁;没有就会一直等待。也就是说,调用notify函数的线程一定要释放掉底层锁,其他线程才会继续执行。

进一步判断gotit,如果为False,说明waiter没有释放,我们从_waiters中剔除它,注意他会和下面的notify()函数同时尝试,报错的话pass就行。

wait_for()断言等待函数

Line27-29:定义了变量 endtime 结束时间和 waittime 等待时间,分别初始化为:None和传入的参数timeout。

result 获得断言的返回值,值得注意的是,断言的运行也是需要不少时间的,这个时间可能超过线程期望等待时间,下面就是要解决此问题。

Line30-40:断言为False则进入循环;

首先waittime,也就是timeout,不能是None;如果是None,那就没啥好说的,直接等待吧;如果不是才要继续判断。

在第一次进入循环的时候,计算出剩余的等待时间(扣除第一次等待断言返回的时间)。

这个时间太长就不能等待了;否则的话,等待剩余时间waittime,进而再计算断言;不管断言结果如何,都只能跳出循环了,因为waittime一定是<=0的。

源码(2-3/3)

def notify(self, n=1):

if not self._is_owned():

raise RuntimeError(“cannot notify on un-acquired lock”)

all_waiters = self._waiters

waiters_to_notify = _deque(_islice(all_waiters, n))

if not waiters_to_notify:

return

for waiter in waiters_to_notify:

waiter.release()

try:

all_waiters.remove(waiter)

except ValueError:

pass

def notify_all(self):

“””Wake up all threads waiting on this condition.

If the calling thread has not acquired the lock when this method

is called, a RuntimeError is raised.

“””

self.notify(len(self._waiters))

notifyAll = notify_all

notify()唤醒线程队列中前n个线程,notify_all()不解释。

Line2-3:自己获得一级锁;

Line4:备份当前线程队列;

Line5:定义新得队列,将前n个线程转移至此;

Line6-7:队列为空则返回,有可能被异常中断了;

Line8-13:循环释放二级锁,wait函数中的wait.acquire()唤醒;最后尝试将线程踢出队列;和wait()两者共同尝试,有一个成功了就行,要是抛出异常了就pass。

3. semaphore

源码(3-1/3)

class Semaphore:

def __init(self, value=1):

if value < 0:

raise ValueError(“semaphore initial value must be >= 0”)

self._cond = Condition(Lock())

self._value = value

Semaphore,俗称信号量管理器,可以传入参数value,默认为1,当然他不等小于0;

首先实例化一个Semaphore类,判断value是否大于0,定义一个私有锁_Condition、和私有变量_value。

源码(3-2/3)

def acquire(self, blocking=True, timeout=None):

if not blocking and timeout is not None:

raise ValueError(“can’t specify timeout for non-blocking acquire”)

rc = False

endtime = None

with self._cond:

while self._value == 0:

if not blocking:

break

if timeout is not None:

if endtime is None:

endtime = _time() + timeout

else:

timeout = endtime - _time()

if timeout <= 0:

break

self._cond.wait(timeout)

else:

self._value -= 1

rc = True

return rc

__enter = acquire

def release(self):

with self._cond:

self._value += 1

self._cond.notify()

def __exit(self, t, v, tb):

self.release()

acquire(), release():这个类中的acquier和release函数并不是传统意义上的获得锁和释放锁,他们在各自方法中分别获得、释放了一次锁。

维护了一个counter计数:它等于 = release()调用次数acquire()调用的数量 + 初始值。例如:当n个线程获得锁,acquire调用了n次,一次都没有调用release()的情况下,n不能大于value。

参数blocking:必要时可以阻止acquire()方法,直到线程返回并且计数器大于0。

注意acquire()函数过程判断传入参数,如果不能阻塞并且timeout还不为none,那肯定报错了。

定义rc返回值、定义endtime;endtime和timeout相互作用的方式,和wait_for()一样;假设两个线程t1和t2。默认情况下,value = 1,t1获得私有锁,while循环不成立,value – 1,rc = True,释放私有锁;此时t2一直等待获得私有锁;但是t1释放私有锁之后,有两种可能:

(1)t2获得,并且value = 0

那么t2进入wait()等待,牛逼的是,进入wait后,会释放一级锁!

释放一级锁之后,t1中的release()就会获得;进一步调用notify函数唤醒t2!

(2)t1的release()获得

这种情况就相当于两个线程各玩各的,互不干扰,没有线程可以唤醒,notify()直接pass就ok!

我画了个简图:

release()函数过程

value加一,调用notify,唤醒一个线程;

__enter__()和__exit__()魔法方法:使得类可以使用“with”上下文管理;其中__exit__()指向release(),还type,value,traceback三个参数,在with抛出异常的时候,分别表示异常的:类型,值和位置;不过也没利用起来

继承类BoundedSemaphore

源码(3-3/3)

class BoundedSemaphore(Semaphore):

def __init(self, value=1):

Semaphore.__init(self, value)

self._initial_value = value

def release(self):

with self._cond:

if self._value >= self._initial_value:

raise ValueError(“Semaphore released too many times”)

self._value += 1

self._cond.notify()

继承于Semaphore。

实例化此类,首先创建一个Semaphore类,和一个私有变量_initial_value,表示初始化的_value值;

重载了Semaphore的release()方法;

而私有变量_initial_value的作用便在这里体现出来,就是release调用不能多于acquier,否则就报错!

后面的就和父类一样了鸭~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值