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 相关文章推荐
在Python下使用Txt2Html实现网页过滤代理的教程
Apr 11 Python
Python写的一个定时重跑获取数据库数据
Dec 28 Python
python用Pygal如何生成漂亮的SVG图像详解
Feb 10 Python
Python cookbook(数据结构与算法)保存最后N个元素的方法
Feb 13 Python
使用pycharm设置控制台不换行的操作方法
Jan 19 Python
opencv python统计及绘制直方图的方法
Jan 21 Python
python2.7的flask框架之引用js&css等静态文件的实现方法
Aug 22 Python
用Python写一个自动木马程序
Sep 17 Python
python给图像加上mask,并提取mask区域实例
Jan 19 Python
matplotlib jupyter notebook 图像可视化 plt show操作
Apr 24 Python
Python Pivot table透视表使用方法解析
Sep 11 Python
基于python定位棋子位置及识别棋子颜色
Jul 26 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
PHP实现RSA签名生成订单功能【支付宝示例】
2017/06/06 PHP
PHP基础之输出缓冲区基本概念、原理分析
2019/06/19 PHP
js url传值中文乱码之解决之道
2009/11/20 Javascript
js下用层来实现select的title提示属性
2010/02/23 Javascript
jQuery实现仿路边灯箱广告图片轮播效果
2015/04/15 Javascript
js实现数组冒泡排序、快速排序原理
2016/03/08 Javascript
jQuery常见的选择器及用法介绍
2016/12/20 Javascript
JS中的数组转变成JSON格式字符串的方法
2017/05/09 Javascript
angular的输入和输出的使用方法
2018/09/22 Javascript
vue-cli 关闭热更新操作
2020/09/18 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
2020/11/11 Javascript
vue组件中节流函数的失效的原因和解决方法
2020/12/02 Vue.js
Python中二维列表如何获取子区域元素的组成
2017/01/19 Python
python数据分析数据标准化及离散化详解
2018/02/26 Python
python3中property使用方法详解
2019/04/23 Python
Django实现跨域请求过程详解
2019/07/25 Python
浅析Python 简单工厂模式和工厂方法模式的优缺点
2020/07/13 Python
Python爬虫爬取糗事百科段子实例分享
2020/07/31 Python
Python自动巡检H3C交换机实现过程解析
2020/08/14 Python
Django多个app urls配置代码实例
2020/11/26 Python
洲际酒店集团大中华区:IHG中国
2016/08/17 全球购物
美国在线咖啡、茶和餐厅供应商:LollicupStore
2018/05/04 全球购物
日本著名的服饰鞋帽综合类购物网站:MAGASEEK
2019/01/09 全球购物
一个SQL面试题
2014/08/21 面试题
Linux不知道文件后缀名怎么判断文件类型
2012/04/26 面试题
请介绍一下WSDL的文档结构
2013/03/17 面试题
平面设计师的工作职责
2013/11/21 职场文书
自动一体化专业求职信
2014/03/15 职场文书
党的群众路线对照检查材料范文
2014/09/24 职场文书
审计局班子四风对照检查材料思想汇报
2014/10/07 职场文书
2014年化妆品销售工作总结
2014/12/01 职场文书
小班上学期幼儿评语
2014/12/30 职场文书
mysql优化
2021/04/06 MySQL
django注册用邮箱发送验证码的实现
2021/04/18 Python
Apache Calcite 实现方言转换的代码
2021/04/24 Servers
零基础学java之带参数以及返回值的方法
2022/04/10 Java/Android