Python中的threading

RLock——重入锁

RLock在Python中的实现是对Lock的封装,具体在类中维护了一个重入次数的变量。一旦一个线程获得一个RLock,该线程再次要求获得该锁时不会阻塞,但该线程获得多少次该锁,则必须释放多少次。一个重入锁必须由获得该锁的线程释放。

源码实现:

数据结构:

  • __block:普通Lock
  • __owner:该锁的拥有者线程
  • __count:该锁被拥有者线程重入的次数

具体方法:

acquire(self, blocking=1): 获取锁
  1. def acquire(self, blocking=1):
  2. me = _get_ident() # 得到调用该函数线程的ID
  3. if self.__owner == me: # 与self.__owner对比
  4. self.__count = self.__count + 1 # 相等,则说明之前该锁就属于该线程,则重入次数自增
  5. return 1 # 返回获取成功
  6. rc = self.__block.acquire(blocking) # 不等的话,则尝试获取__block锁
  7. if rc: # 如果获取成功
  8. self.__owner = me # 则将该锁的拥有者赋值为该线程
  9. self.__count = 1 # 并将重入次数自增
  10. return rc # 返回获取成功与否
release(self):释放锁
  1. def release(self):
  2. if self.__owner != _get_ident(): # 如果当前该锁的拥有者线程不是调用该函数的线程,抛出异常
  3. raise RuntimeError("cannot release un-acquired lock")
  4. self.__count = count = self.__count - 1 # 否则,重入次数自减
  5. if not count: # 当重入次数为0时
  6. self.__owner = None # 该锁拥有者为None
  7. self.__block.release() # 且释放__block

Condition——条件变量

Condition对象允许一个或多个线程等待直到它们被其它线程通知,然后继续执行。Condition除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。可以将Condition看成一个有条件的锁,其中增加了当不满足条件时,需等待的接口。

一个线程首先调用condition的acquire方法,然后判断一些条件,如不满足则wait;如果条件满足,进行一些处理,通过notify方法来通知其他线程。

源码实现:

数据结构:

  • __lock:Lock或者RLock实例,Condition中锁的实现
  • __waiters:等待的线程

具体方法:

wait(self, timeout=None):条件不满足时等待
  1. def wait(self, timeout=None):
  2. if not self._is_owned(): # 调用该函数前,必须先获取锁
  3. raise RuntimeError("cannot wait on un-acquired lock")
  4. waiter = _allocate_lock() # 申请一个普通的Lock
  5. waiter.acquire() # 首先先获取了,再获取需阻塞
  6. self.__waiters.append(waiter) # 即将该线程挂到锁上面,再把锁弄进等待队列
  7. saved_state = self._release_save() # 释放锁,保存锁的一些状态,当为重入锁时,则需保存锁的拥有者和重入次数状态
  8. try: # restore state no matter what (e.g., KeyboardInterrupt)
  9. if timeout is None: # 当timeout为空,则代表永久阻塞
  10. waiter.acquire() # 再获取,即该线程会阻塞到该锁上
  11. else:
  12. # Balancing act: We can't afford a pure busy loop, so we
  13. # have to sleep; but if we sleep the whole timeout time,
  14. # we'll be unresponsive. The scheme here sleeps very
  15. # little at first, longer as time goes on, but never longer
  16. # than 20 times per second (or the timeout time remaining).
  17. endtime = _time() + timeout
  18. delay = 0.0005 # 500 us -> initial delay of 1 ms
  19. while True:
  20. gotit = waiter.acquire(0)
  21. if gotit: 如果在规定时间内有其他线程通知了该线程,则退出
  22. break
  23. remaining = endtime - _time()
  24. if remaining <= 0: # 如果超时,则退出
  25. break
  26. delay = min(delay * 2, remaining, .05) # 获取需要的睡眠时间,每次延长
  27. _sleep(delay)
  28. if not gotit:
  29. try:
  30. self.__waiters.remove(waiter)
  31. except ValueError:
  32. pass
  33. finally:
  34. self._acquire_restore(saved_state) # 最后竞争该锁,恢复状态
notify(self, n=1):唤醒n个线程
  1. def notify(self, n=1):
  2. if not self._is_owned(): # 必须拥有锁的状态下,才能调用notify
  3. raise RuntimeError("cannot notify on un-acquired lock")
  4. __waiters = self.__waiters
  5. waiters = __waiters[:n] # 唤醒前n个
  6. if not waiters:
  7. return
  8. for waiter in waiters:
  9. waiter.release() # 唤醒
  10. try:
  11. __waiters.remove(waiter) # 从等待的队列中移除
  12. except ValueError:
  13. pass
notifyAll(self):唤醒所有在该condition上等待的线程
  1. def notifyAll(self):
  2. self.notify(len(self.__waiters))

Semaphore——信号量

Semaphore维护了一个计数器,代表release调用的次数 - acquire调用次数 + 计数器初始值。最简单的应用为操作系统中,某个资源(例如打印机)的个数为n,线程的数量为m,当线程抢占资源时,可以使用Semaphore来保证资源利用的合理性。

源码实现:

数据结构:

  • __cond: 为Condition(Lock()),当资源数不够时,调用__condwait()方法来等待其他线程释放资源的通知(notify())
  • __value: 为int型,代表初始资源的个数

具体方法:

acqiure(self, blocking=1):抢占其中一个资源
  1. def acquire(self, blocking=1):
  2. rc = False
  3. with self.__cond: # 首先抢占条件变量的锁,以下代码为多个线程互斥访问
  4. while self.__value == 0:
  5. if not blocking:
  6. break
  7. self.__cond.wait() # 当资源为0时, 则等待别的线程释放,唤醒则继续判断资源个数
  8. else:
  9. self.__value = self.__value - 1 # 否则资源足够,则减一,表示获取一个资源
  10. rc = True
  11. return rc
release(self):释放一个资源
  1. def release(self):
  2. with self.__cond: # 同样,先抢占条件变量锁,以下代码互斥访问
  3. self.__value = self.__value + 1 # 资源数加一,表示该线程用好资源了
  4. self.__cond.notify() # 唤醒其中一个线程叫它来抢资源

Event——事件监听

Event机制类似于事件的监听机制,其他线程调用wait()方法阻塞监听一个事件的发生,当某个线程检测到事件的发生,会向所有等待的线程发送一个信号,等待线程重新唤醒继续执行。

源码实现

数据结构

  • __cond: 为Condition(Lock()),当事件未发生时,调用__condwait()方法阻塞等待事件发生
  • __flag:初始值为false,代表事件未发生,当发生时,置为true

具体方法

wait(self, timeout=None):等待直到__flag为true
  1. def wait(self, timeout=None):
  2. self.__cond.acquire() # 抢占条件变量的锁
  3. try:
  4. if not self.__flag: # 查看事件发生与否
  5. self.__cond.wait(timeout) # 如未发生,则阻塞
  6. return self.__flag
  7. finally:
  8. self.__cond.release()
set(self):设置__flag为true,表明事件的发生
  1. def set(self):
  2. self.__cond.acquire() # 抢占条件变量的锁
  3. try:
  4. self.__flag = True # 设置事件发生
  5. self.__cond.notify_all() # 通知所有等待的线程
  6. finally:
  7. self.__cond.release()

Python中的threading的更多相关文章

  1. python中的threading模块使用说明

    这段时间使用python做串口的底层库,用到了多线程,对这部分做一下总结.实际用完了后再回过头去看python的官方帮助文档,感觉受益匪浅,把里面的自己觉得有用的一些关键点翻译出来,留待后续查验.th ...

  2. Python多线程(threading模块)

    线程(thread)是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. ...

  3. python中的进程、线程(threading、multiprocessing、Queue、subprocess)

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  4. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  5. Python中的multiprocessing和threading

    Python中的multiprocessing和threading分别使用来实现多进程编程和多线程编程的.其中threading比较简单,而前者比较繁琐. 下面,我们进行一下分析: 多线程--thre ...

  6. Python标准模块--threading

    1 模块简介 threading模块在Python1.5.2中首次引入,是低级thread模块的一个增强版.threading模块让线程使用起来更加容易,允许程序同一时间运行多个操作. 不过请注意,P ...

  7. python中的IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

  8. python 线程之 threading(四)

    python 线程之 threading(三) http://www.cnblogs.com/someoneHan/p/6213100.html中对Event做了简单的介绍. 但是如果线程打算一遍一遍 ...

  9. 线程安全及Python中的GIL

    线程安全及Python中的GIL 本博客所有内容采用 Creative Commons Licenses 许可使用. 引用本内容时,请保留 朱涛, 出处 ,并且 非商业 . 点击 订阅 来订阅本博客. ...

随机推荐

  1. Makefile <网络转载>

    陈皓 (CSDN)概述——什 么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和 professional的 ...

  2. 第五章 征服数据库(Spring对DB的使用)——开发持久层

    本章内容: 定义Spring对数据库访问的支持 配置数据库资源 使用Spring的JDBC模板 在几乎所有的企业级应用中,都需要构建数据持久层.现在意义上的数据持久层是指把对象或者数据保存到数据库中, ...

  3. Office 365 系列五 -------- Imap邮箱迁移步骤

    当客户购买了我们的Office 365之后,第一个功能必然是会用我们的企业邮箱,如果企业之前是用 263.腾讯.网易等的邮件厂商的话,必然会涉及到邮件的迁移, 其实说到邮箱迁移,我们办法很多,如果人数 ...

  4. DSP中的段

    虽然,C语言是一种相对高效的高级语言,并且TI提供的C编译器还结合硬件特点支持三级优化功能,但生成的汇编代码效率仍可能会不尽人意.如作者预使用环型缓冲区管理功能,这就要求该缓冲区应被定位到相对特定的位 ...

  5. fiddler抓取Android 真机app数据包

    fiddler功能强大 不仅能抓pc上的请求还能抓取手机上的请求.下面以fiddler4 +android手机为例介绍一下 手机抓包. 官网下载fiddler后下一步下一步安装成功. 首先是fiddl ...

  6. oracle+ibatis 批量插入-支持序列自增

    首先请先看我前面一篇帖子了解oracle批量插入的sql:[oracle 批量插入-支持序列自增] 我用的ibatis2.0,sqlMap文件引入的标签如下: <!DOCTYPE sqlMap ...

  7. Reveal的使用及破解方法

    Reveal的使用其实真的很简单,就如第一张镇楼图的效果一样.中间是3D可视化当前APP页面的视图,左侧则是这些UI元素和层次结构,而右侧则是View的属性,你可以修改View的颜色.frame等等, ...

  8. matlab struct结构体用法

    结构体的赋值: 结构体的赋值,这里不建议用下面这种形式进行统一赋值, s = sturct('field1',values1,'field2',values2,-) 而是建议直接赋值,就是对每一个属性 ...

  9. object to 字符串json

    package com.beijxing.TestMain; import com.beijxing.entity.Student; import com.google.gson.Gson; impo ...

  10. Action名称的搜索顺序

    假设当前的路径的URL是:http://StrutsDemo01/path1/path2/path3/test.action 步骤1.首先寻找命名空间(namespace)为 /path1/path2 ...