一.思路概述
Python线程创建
使用threading模块的Thread类的接口如下
class Thread( group=None, target=None, name=None, args=(), kwargs={})
需要关注的参数是target和args. target 是需要子线程运行的目标函数,args是函数的参数,以tuple的形式传递。
以下代码创建一个指向函数worker的子线程
def worker(tid,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个读卡器,每个读卡器收费器每次扣除用户一块钱进入总账中,每个读卡器每天一共被刷1000000次。账户原有100块。所以最后的总账应该为10000100。
三.源码实现
#!/usr/bin/env python
#encoding: utf-8
import time, datetime, threading
#each worker thread exec 1000000 times
def worker(tid, account):
global g_mutex
for i in range(1000000):
g_mutex.acquire()
if i%500000 == 0:
print 'worker thread', tid, 'count', i
account.deposite(1)
g_mutex.release()
#account operation class
class Account:
def __init__(self, base):
self.m_amount = base
def deposite(self, amount):
self.m_amount += amount;
def withdraw(self, amount):
self.m_amount -= amount
#main entry point...
if __name__ == '__main__':
global g_mutex
count = 0;
tm_start = datetime.datetime.now()
print 'Main Thread start at:', tm_start
#initialize thread pool
thread_pool = []
#initialize mutex
g_mutex = threading.Lock()
#init thread items
acc = Account(100)
for i in range(10):
t = threading.Thread(target=worker, args=(i, acc));
thread_pool.append(t)
#start worker threads one by one
for i in range(10):
thread_pool[i].start()
#reclaim all worker threads resource
for i in range(10):
threading.Thread.join(thread_pool[i])
#statistics
tm_stop = datetime.datetime.now()
print 'count=', acc.m_amount
print 'Main Thread end at:', tm_stop
print 'time consumption ', tm_stop-tm_start
四.运行效果截图
注意在多线程环境下print输出要放到互斥锁下面操作,才不会导致导致各线程的打印信息混乱.
参考文献