Python中尝试多线程编程的一个简明例子


Posted in Python onApril 07, 2015

综述
    多线程是程序设计中的一个重要方面,尤其是在服务器Deamon程序方面。无论何种系统,线程调度的开销都比传统的进程要快得多。
  Python可以方便地支持多线程。可以快速创建线程、互斥锁、信号量等等元素,支持线程读写同步互斥。美中不足的是,Python的运行在Python 虚拟机上,创建的多线程可能是虚拟的线程,需要由Python虚拟机来轮询调度,这大大降低了Python多线程的可用性。希望高版本的Python可以 解决这个问题,发挥多CPU的最大效率。
  网上有些朋友说要获得真正多CPU的好处,有两种方法:
  1.可以创建多个进程而不是线程,进程数和cpu一样多。
  2.使用Jython 或 IronPython,可以得到真正的多线程。
  闲话少说,下面看看Python如何建立线程
  Python线程创建
  使用threading模块的 Thread类
  类接口如下

class  Thread( group=None, target=None, name=None, args=(), kwargs={})

 需要关注的参数是target和args. target 是需要子线程运行的目标函数,args是函数的参数,以tuple的形式传递。
  以下代码创建一个指向函数worker 的子线程
def worker(a_tid,a_account): 

     ... 

th = threading.Thread(target=worker,args=(i,acc) ) ;

启动这个线程

th.start()

等待线程返回
threading.Thread.join(th)

或者th.join()
如果你可以对要处理的数据进行很好的划分,而且线程之间无须通信,那么你可以使用:创建=》运行=》回收的方式编写你的多线程程序。但是如果线程之间需要访问共同的对象,则需要引入互斥锁或者信号量对资源进行互斥访问。
 下面讲讲如何创建互斥锁
创建锁
g_mutex = threading.Lock() 

  ....

使用锁 
    
for  ... : 

        #锁定,从下一句代码到释放前互斥访问 

        g_mutex.acquire() 

        a_account.deposite(1) 

        #释放 

        g_mutex.release()

最后,模拟一个公交地铁IC卡缴车费的多线程程序
  有10个读卡器,每个读卡器收费器每次扣除用户一块钱进入总账中,每读卡器每天一共被刷10000000次。账户原有100块。所以最后的总账应该为10000100。先不使用互斥锁来进行锁定(注释掉了锁定代码),看看后果如何。
import time,datetime
import threading
 
def worker(a_tid,a_account):
 global g_mutex
 print("Str " , a_tid, datetime.datetime.now() )
 for i in range(1000000):
  #g_mutex.acquire()
  a_account.deposite(1)
  #g_mutex.release()
 print("End " , a_tid , datetime.datetime.now() )
  
class Account:
 def __init__ (self, a_base ):
  self.m_amount=a_base
 def deposite(self,a_amount):
  self.m_amount+=a_amount
 def withdraw(self,a_amount):
  self.m_amount-=a_amount 
 
if __name__ == "__main__":
 global g_mutex
 count = 0
 dstart = datetime.datetime.now()
 print("Main Thread Start At: ", dstart)
 #init thread_pool
 thread_pool = []
 #init mutex
 g_mutex = threading.Lock()
 # init thread items
 acc = Account(100)
 for i in range(10):
  th = threading.Thread(target=worker,args=(i,acc) ) ;
  thread_pool.append(th)
   
 # start threads one by one  
 for i in range(10):
  thread_pool[i].start()
  
 #collect all threads
 for i in range(10):
  threading.Thread.join(thread_pool[i])
 dend = datetime.datetime.now()
 print("count=", acc.m_amount)
 print("Main Thread End at: ", dend, " time span ", dend-dstart)

注意,先不用互斥锁进行临界段访问控制,运行结果如下:
Python中尝试多线程编程的一个简明例子

从结果看到,程序确实是多线程运行的。但是由于没有对对象Account进行互斥访问,所以结果是错误的,只有3434612,比原预计少了很多。

打开锁后:
Python中尝试多线程编程的一个简明例子

这次可以看到,结果正确了。运行时间比不进行互斥多了很多,不过这也是同步的代价。
同时发现,写多线程,多进程类的程序,不能用自带的idle来运行。会有错误。

Python 相关文章推荐
仅用500行Python代码实现一个英文解析器的教程
Apr 02 Python
浅谈Python2获取中文文件名的编码问题
Jan 09 Python
tensorflow入门之训练简单的神经网络方法
Feb 26 Python
python增加矩阵维度的实例讲解
Apr 04 Python
python使用Flask操作mysql实现登录功能
May 14 Python
python-itchat 获取微信群用户信息的实例
Feb 21 Python
树莓派使用USB摄像头和motion实现监控
Jun 22 Python
对Python生成器、装饰器、递归的使用详解
Jul 19 Python
Python openpyxl读取单元格字体颜色过程解析
Sep 03 Python
Python 实现Image和Ndarray互相转换
Feb 19 Python
如何用 Python 处理不平衡数据集
Jan 04 Python
python读取mnist数据集方法案例详解
Sep 04 Python
Python的Flask框架中Flask-Admin库的简单入门指引
Apr 07 #Python
用Python实现一个简单的线程池
Apr 07 #Python
浅谈Python程序与C++程序的联合使用
Apr 07 #Python
浅要分析Python程序与C程序的结合使用
Apr 07 #Python
python实现根据用户输入从电影网站获取影片信息的方法
Apr 07 #Python
python中列表元素连接方法join用法实例
Apr 07 #Python
简单介绍Python中的filter和lambda函数的使用
Apr 07 #Python
You might like
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
PHP的一个基础知识 表单提交
2011/07/04 PHP
ECMall支持SSL连接邮件服务器的配置方法详解
2014/05/19 PHP
PHP彩蛋信息介绍和阻止泄漏的方法(隐藏功能)
2014/08/06 PHP
PHP 表单提交及处理表单数据详解及实例
2016/12/27 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
关于jquery append() html时的小问题的解决方法
2010/12/16 Javascript
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
js获取控件位置以及不同浏览器中的差别介绍
2013/08/08 Javascript
JavaScript 作用域链解析
2014/11/13 Javascript
JavaScript 面向对象与原型
2015/04/10 Javascript
JavaScript中的getMilliseconds()方法使用详解
2015/06/10 Javascript
js实现类似MSN提示的页面效果代码分享
2015/08/24 Javascript
JS实现黑色大气的二级导航菜单效果
2015/09/18 Javascript
基于HTML5上使用iScroll实现下拉刷新,上拉加载更多
2016/05/21 Javascript
AngularJS轻松实现双击排序的功能
2016/08/30 Javascript
深入理解Vue 单向数据流的原理
2017/11/09 Javascript
Vue实现美团app的影院推荐选座功能【推荐】
2018/08/29 Javascript
python实现迭代法求方程组的根过程解析
2019/11/25 Javascript
vue搜索页开发实例代码详解(热门搜索,历史搜索,淘宝接口演示)
2020/04/11 Javascript
[34:39]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#1COL VS EG第二局
2016/03/05 DOTA
[34:47]完美世界DOTA2联赛PWL S2 Magma vs LBZS 第一场 11.18
2020/11/18 DOTA
python删除指定类型(或非指定)的文件实例详解
2015/07/06 Python
python正则表达式的使用
2017/06/12 Python
python3实现TCP协议的简单服务器和客户端案例(分享)
2017/06/14 Python
详解python中TCP协议中的粘包问题
2019/03/22 Python
python查看文件大小和文件夹内容的方法
2019/07/08 Python
opencv3/Python 稠密光流calcOpticalFlowFarneback详解
2019/12/11 Python
html5教程调用绘图api画简单的圆形代码分享
2013/12/04 HTML / CSS
JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
2013/07/02 面试题
岗位职责的定义
2013/11/10 职场文书
九年级化学教学反思
2014/01/28 职场文书
学校募捐倡议书
2014/05/14 职场文书
2016年员工政治思想表现评语
2015/12/02 职场文书
怎样评估创业计划书是否有可行性?
2019/08/07 职场文书
使用CSS实现小三角边框原理解析
2021/11/07 HTML / CSS