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学习手册中的python多态示例代码
Jan 21 Python
Python开发实例分享bt种子爬虫程序和种子解析
May 21 Python
Windows系统下安装Python的SSH模块教程
Feb 05 Python
Python函数式编程指南(二):从函数开始
Jun 24 Python
基于Python实现一个简单的银行转账操作
Mar 06 Python
python 与GO中操作slice,list的方式实例代码
Mar 20 Python
Python定时任务APScheduler的实例实例详解
Jul 22 Python
centos7之Python3.74安装教程
Aug 15 Python
python3的数据类型及数据类型转换实例详解
Aug 20 Python
Django 自动生成api接口文档教程
Nov 19 Python
python更新数据库中某个字段的数据(方法详解)
Nov 18 Python
Python学习之异常中的finally使用详解
Mar 16 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/02/05 PHP
php中文繁体和简体相互转换的方法
2015/03/21 PHP
PHP基于进程控制函数实现多线程
2020/12/09 PHP
15 个 JavaScript Web UI 库
2010/05/19 Javascript
JavaScript高级程序设计 客户端存储学习笔记
2011/09/10 Javascript
JS中的substring和substr函数的区别说明
2013/05/07 Javascript
html页面显示年月日时分秒和星期几的两种方式
2013/08/20 Javascript
JavaScript计时器示例分析
2015/02/05 Javascript
javascript实现的多个层切换效果通用函数实例
2015/07/06 Javascript
不依赖Flash和任何JS库实现文本复制与剪切附源码下载
2015/10/09 Javascript
jQuery无刷新分页完整实例代码
2015/10/27 Javascript
js实现简易聊天对话框
2017/08/17 Javascript
基于javascript 显式转换与隐式转换(详解)
2017/12/15 Javascript
angularjs通过过滤器返回超链接的方法
2018/10/26 Javascript
Bootstrap的aria-label和aria-labelledby属性实例详解
2018/11/02 Javascript
浅析TypeScript 命名空间
2020/03/19 Javascript
js 压缩图片的示例(只缩小体积,不更改图片尺寸)
2020/10/21 Javascript
[49:20]2014 DOTA2国际邀请赛中国区预选赛5.21 CIS VS TongFu
2014/05/22 DOTA
[57:50]DOTA2上海特级锦标赛主赛事日 - 4 胜者组决赛Secret VS Liquid第二局
2016/03/05 DOTA
Python通过PIL获取图片主要颜色并和颜色库进行对比的方法
2015/03/19 Python
详解Python的单元测试
2015/04/28 Python
python下MySQLdb用法实例分析
2015/06/08 Python
使用python在本地电脑上快速处理数据
2017/06/22 Python
Python之批量创建文件的实例讲解
2018/05/10 Python
python获取服务器响应cookie的实例
2018/12/28 Python
Django多数据库的实现过程详解
2019/08/01 Python
Python多线程多进程实例对比解析
2020/03/12 Python
Python中免验证跳转到内容页的实例代码
2020/10/23 Python
意大利运动服减价商店:ScontoSport
2020/03/10 全球购物
哪些情况下不应该使用索引
2015/07/20 面试题
介绍一下Linux文件的记录形式
2012/04/18 面试题
2014年加油站工作总结
2014/12/04 职场文书
护士个人总结范文
2015/02/13 职场文书
2015小学五年级班主任工作总结
2015/05/21 职场文书
公司趣味运动会开幕词
2016/03/04 职场文书
Python移位密码、仿射变换解密实例代码
2021/06/27 Python