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中的文档测试模块
Apr 28 Python
Python中装饰器兼容加括号和不加括号的写法详解
Jul 05 Python
详谈Python高阶函数与函数装饰器(推荐)
Sep 30 Python
python 除法保留两位小数点的方法
Jul 16 Python
Python Pandas批量读取csv文件到dataframe的方法
Oct 08 Python
python 使用正则表达式按照多个空格分割字符的实例
Dec 20 Python
python实现祝福弹窗效果
Apr 07 Python
Django自定义用户登录认证示例代码
Jun 30 Python
Python warning警告出现的原因及忽略方法
Jan 31 Python
python如何处理程序无法打开
Jun 16 Python
Python unittest基本使用方法代码实例
Jun 29 Python
利用Python实现字幕挂载(把字幕文件与视频合并)思路详解
Oct 21 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服务器页面间跳转实现方法
2012/08/02 PHP
用Php编写注册后Email激活验证的实例代码
2013/03/11 PHP
PHP变量赋值、代入给JavaScript中的变量
2015/06/29 PHP
jquery一般方法介绍 入门参考
2011/06/21 Javascript
取得窗口大小 兼容所有浏览器的js代码
2011/08/09 Javascript
javascript学习笔记(七) js函数介绍
2012/06/19 Javascript
js判断运行jsp页面的浏览器类型以及版本示例
2013/10/30 Javascript
AngularJS基础学习笔记之指令
2015/05/10 Javascript
jQuery hover事件简单实现同时绑定2个方法
2016/06/07 Javascript
Web程序员必备的7个JavaScript函数
2016/06/14 Javascript
HTML Table 空白单元格补全的简单实现
2016/10/13 Javascript
jQuery实现全选、反选和不选功能
2017/08/16 jQuery
React Native 使用Fetch发送网络请求的示例代码
2017/12/02 Javascript
微信小程序地图实现展示线路
2020/07/29 Javascript
vue 使用localstorage实现面包屑的操作
2020/11/16 Javascript
Python 正则表达式(转义问题)
2014/12/15 Python
Python的批量远程管理和部署工具Fabric用法实例
2015/01/23 Python
Python基于更相减损术实现求解最大公约数的方法
2018/04/04 Python
python requests.post带head和body的实例
2019/01/02 Python
pyqt5 QScrollArea设置在自定义侧(任何位置)
2019/09/25 Python
python读取mysql数据绘制条形图
2020/03/25 Python
在Keras中利用np.random.shuffle()打乱数据集实例
2020/06/15 Python
Python如何解除一个装饰器
2020/08/07 Python
HTML5语音识别标签写法附图
2013/11/18 HTML / CSS
基于Html5实现的语音搜索功能
2019/05/13 HTML / CSS
加拿大大码女装购物网站:Penningtons
2020/12/26 全球购物
优秀研究生自我鉴定
2013/12/04 职场文书
《桂林山水》教学反思
2014/02/08 职场文书
会计专业职业规划:规划自我赢取未来
2014/02/12 职场文书
班主任工作经验交流材料
2014/05/13 职场文书
试用期员工工作自我评价
2014/09/10 职场文书
大二学生自我检讨书
2014/10/23 职场文书
2016母亲节感恩话语
2015/12/09 职场文书
篮球拉拉队口号
2015/12/25 职场文书
2019年“我为祖国点赞”演讲稿(3篇)
2019/09/26 职场文书
深入浅出讲解Java8函数式编程
2022/01/18 Java/Android