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实现的Google IP 可用性检测脚本
Apr 23 Python
Python字符编码判断方法分析
Jul 01 Python
对python中dict和json的区别详解
Dec 18 Python
Python 日期区间处理 (本周本月上周上月...)
Aug 08 Python
python 求10个数的平均数实例
Dec 16 Python
利用python中集合的唯一性实现去重
Feb 11 Python
Python垃圾回收机制三种实现方法
Apr 27 Python
Python代码中如何读取键盘录入的值
May 27 Python
keras多显卡训练方式
Jun 10 Python
Python环境管理virtualenv&virtualenvwrapper的配置详解
Jul 01 Python
python字符串拼接+和join的区别详解
Dec 03 Python
python超详细实现完整学生成绩管理系统
Mar 17 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
图形数字验证代码
2006/10/09 PHP
扩展你的 PHP 之入门篇
2006/12/04 PHP
PHP分页类集锦
2014/11/18 PHP
PHP之正则表达式捕获组与非捕获组(详解)
2015/07/29 PHP
PHP数据对象PDO操作技巧小结
2016/09/27 PHP
PHP按符号截取字符串的指定部分的实现方法
2018/09/10 PHP
总结AJAX相关JS代码片段和浏览器模型
2007/08/15 Javascript
Javascript异步表单提交,图片上传,兼容异步模拟ajax技术
2010/05/10 Javascript
基于jquery的禁用右键、文本选择功能、复制按键的实现代码
2013/08/27 Javascript
javascript中call apply 的应用场景
2015/04/16 Javascript
js实现千分符和保留几位小数的简单实例
2016/08/01 Javascript
Bootstrap 模态对话框只加载一次 remote 数据的完美解决办法
2017/07/09 Javascript
详解Vue快速零配置的打包工具——parcel
2018/01/16 Javascript
使用VueRouter的addRoutes方法实现动态添加用户的权限路由
2019/06/03 Javascript
jQuery实现input[type=file]多图预览上传删除等功能
2019/08/02 jQuery
vue简单封装axios插件和接口的统一管理操作示例
2020/02/02 Javascript
[05:05]DOTA2亚洲邀请赛 战队出场仪式
2015/02/07 DOTA
[04:16]完美世界DOTA2联赛PWL S2 集锦第一期
2020/11/23 DOTA
Flask框架的学习指南之制作简单blog系统
2016/11/20 Python
TensorFlow实现AutoEncoder自编码器
2018/03/09 Python
使用Python横向合并excel文件的实例
2018/12/11 Python
python正则表达式去除两个特殊字符间的内容方法
2018/12/24 Python
Django stark组件使用及原理详解
2019/08/22 Python
Python Numpy库常见用法入门教程
2020/01/16 Python
使用tensorflow实现VGG网络,训练mnist数据集方式
2020/05/26 Python
python读取excel进行遍历/xlrd模块操作
2020/07/12 Python
瑞典灯具和照明网上商店:Lamp24.se
2018/03/17 全球购物
匡威德国官网:Converse德国
2019/01/26 全球购物
教师现实表现材料
2014/02/14 职场文书
个人廉洁自律承诺书
2014/03/27 职场文书
拔河比赛口号
2014/06/10 职场文书
六年级小学生评语
2014/12/26 职场文书
复试通知单模板
2015/04/24 职场文书
教师病假条范文
2015/08/17 职场文书
大队委员竞选演讲稿
2015/11/20 职场文书
剧场版《转生恶役只好拔除破灭旗标》公开最新视觉图 2023年上映
2022/04/02 日漫