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开发编码规范
Sep 08 Python
深入理解NumPy简明教程---数组2
Dec 17 Python
Python编程实现输入某年某月某日计算出这一天是该年第几天的方法
Apr 18 Python
python 中的int()函数怎么用
Oct 17 Python
python3+dlib实现人脸识别和情绪分析
Apr 21 Python
解决python报错MemoryError的问题
Jun 26 Python
python3.6使用pickle序列化class的方法
Oct 22 Python
PyCharm配置mongo插件的方法
Nov 30 Python
Python字典循环添加一键多值的用法实例
Jan 20 Python
Python3 selenium 实现QQ群接龙自动化功能
Apr 17 Python
python类共享变量操作
Sep 03 Python
opencv 分类白天与夜景视频的方法
Jun 05 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 截取字符串专题集合
2010/08/19 PHP
应用开发中涉及到的css和php笔记分享
2011/08/02 PHP
php 模拟 asp.net webFrom 按钮提交事件实例
2014/10/13 PHP
PHP实现Javascript中的escape及unescape函数代码分享
2015/02/10 PHP
php实现通过ftp上传文件
2015/06/19 PHP
Yii2.0中使用js异步删除示例
2017/03/10 PHP
PHP7数组的底层实现示例
2019/08/25 PHP
jquery中选择块并改变属性值的方法
2013/07/31 Javascript
jquery定时滑出可最小化的底部提示层特效代码
2013/10/02 Javascript
JS正则表达式大全(整理详细且实用)
2013/11/14 Javascript
ZeroClipboard插件实现多浏览器复制功能(支持firefox、chrome、ie6)
2014/08/30 Javascript
浅谈JavaScript 浏览器对象
2016/06/03 Javascript
jquery.serialize() 函数语法及简单实例
2016/07/08 Javascript
ajax +NodeJS 实现图片上传实例
2017/06/06 NodeJs
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
JS实现留言板功能[楼层效果展示]
2017/12/27 Javascript
vue.js 嵌套循环、if判断、动态删除的实例
2018/03/07 Javascript
解决vue router组件状态刷新消失的问题
2018/08/01 Javascript
微信小程序自定义菜单切换栏tabbar组件代码实例
2019/12/30 Javascript
vue实现购物车案例
2020/05/30 Javascript
基于JavaScript实现随机点名器
2021/02/25 Javascript
[46:47]2014 DOTA2国际邀请赛中国区预选赛 DT VS HGT
2014/05/22 DOTA
Python3实现简单可学习的手写体识别(实例讲解)
2017/10/21 Python
在Python中居然可以定义两个同名通参数的函数
2019/01/31 Python
python 执行终端/控制台命令的例子
2019/07/12 Python
Python魔法方法 容器部方法详解
2020/01/02 Python
python开发前景如何
2020/06/11 Python
白宫黑市官网:White House Black Market
2016/11/17 全球购物
行政人员工作职责
2013/12/05 职场文书
专业幼师实习生自我鉴定范文
2013/12/08 职场文书
导游的职业规划书范文
2013/12/27 职场文书
铁路安全事故反思
2014/04/26 职场文书
优秀教导主任事迹材料
2014/05/09 职场文书
家长给学校的建议书
2014/05/15 职场文书
学生个人评语大全
2015/01/04 职场文书
幼儿园开学报名通知
2015/07/16 职场文书