Python学习笔记--多线程编程,thread

时间:2022-07-14 17:34:58

简介:

        Python提供了thread模块,threading模块与queue模块进行多线程编程。queue模块用于线程间的通信,前两者可以创建线程,不过由于thread模块偏底层,需要手动去完成很多任务,而且同步机制不如threading模块好用,所以建议选择threading模块。

        threading模块中,选择Thread类来创建线程(三种方法):创建一个Thread的实例,并传入一个函数;创建一个Thread的实例,并传入一个可调用的类对象;从Thread派生出一个子类,创建一个这个子类的实例。(代码来自core Python programming)(Python3.3)

创建一个Thread的实例,并传入一个函数:

import threading
from time import sleep,ctime

loops=[4,2]

def loop(nloop, nsec):
print('start loop',nloop,'at',ctime())
sleep(nsec)
print('loop',nloop,'done at:',ctime())

def test():
print('starting at:',ctime())
threads=[]
nloops=range(len(loops))

for i in nloops:
t=threading.Thread(target=loop,args=(i,loops[i]))
threads.append(t)

for i in nloops:
threads[i].start()

for i in nloops:
threads[i].join() #当前process或者thread遇到join()函数时会暂停(挂起),直到这个join()函数连接的thread结束;join(timeout=None)中的timeout参数如果设置了,则会等到设置的时间长度,直到超时或者thread结束,开始运行接下来的代码

print('all done at',ctime())

if __name__=='__main__':
test()

结果:

>>> 
starting at: Thu Aug 15 01:34:20 2013
start loopstart loop 01 atat Thu Aug 15 01:34:20 2013Thu Aug 15 01:34:20 2013

loop 1 done at: Thu Aug 15 01:34:22 2013
loop 0 done at: Thu Aug 15 01:34:24 2013
all done at Thu Aug 15 01:34:25 2013

创建一个Thread的实例,并传入一个可调用的类对象:
较第一种更面向对象一点,更灵活。

import threading
from time import sleep,ctime

loops=[4,2]

class ThreadFunc(object):
def __init__(self,func,args,name=''):
self.name=name
self.func=func
self.args=args

def __call__(self):
self.func(*self.args)

def loop(nloop, nsec):
print('start loop',nloop,'at',ctime())
sleep(nsec)
print('loop',nloop,'done at:',ctime())

def test():
print('starting at:',ctime())
threads=[]
nloops=range(len(loops))

for i in nloops:
t=threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
threads.append(t)

for i in nloops:
threads[i].start()

for i in nloops:
threads[i].join()

print('all done at',ctime())

if __name__=='__main__':
test()

结果:

>>> 
starting at: Thu Aug 15 01:58:32 2013
start loopstart loop 01 atat Thu Aug 15 01:58:32 2013Thu Aug 15 01:58:32 2013

loop 1 done at: Thu Aug 15 01:58:34 2013
loop 0 done at: Thu Aug 15 01:58:36 2013
all done at Thu Aug 15 01:58:36 2013

从Thread派生出一个子类,创建一个这个子类的实例:

import threading
from time import sleep,ctime

loops=[4,2]

class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
threading.Thread.__init__(self)
self.name=name
self.func=func
self.args=args

def run(self):
self.func(*self.args)

def loop(nloop, nsec):
print('start loop',nloop,'at',ctime())
sleep(nsec)
print('loop',nloop,'done at:',ctime())

def test():
print('starting at:',ctime())
threads=[]
nloops=range(len(loops))

for i in nloops:
t=MyThread(loop,(i,loops[i]),loop.__name__)
threads.append(t)

for i in nloops:
threads[i].start()

for i in nloops:
threads[i].join()

print('all done at',ctime())

if __name__=='__main__':
test()

结果:

>>> 
starting at: Thu Aug 15 02:15:18 2013
start loopstart loop 1 at Thu Aug 15 02:15:18 2013
0 at Thu Aug 15 02:15:18 2013
loop 1 done at: Thu Aug 15 02:15:20 2013
loop 0 done at: Thu Aug 15 02:15:22 2013
all done at Thu Aug 15 02:15:22 2013

单线程、多线程速度对比:

对多线程使用第三者创建线程的方法。计算斐波纳挈、阶乘、累加和的结果:

首先,编写一个单独的模块myThread.py,专门生成线程,然后使用的时候,只需要import myThread 就可以了。

import threading
from time import sleep,ctime

class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
threading.Thread.__init__(self)
self.name=name
self.func=func
self.args=args

def getResult(self):
return self.res
def run(self):
print('starting',self.name,'at:',ctime())
self.res=self.func(*self.args)
print(self.name,'finished at:',ctime()) #end of module myThread
创建线程并计算:

from myThread import MyThread
from time import ctime,sleep

def fib(x):
sleep(0.005)
if x<2:
return 1
return (fib(x-2)+fib(x-1))

def fac(x):
sleep(0.1)
if x<2:
return 1
return (x*fac(x-1))

def sumF(x):
sleep(0.1)
if x<2:
return 1
return (x+sumF(x-1))

funcs=[fib, fac, sumF]
n=12

def test():
nfuncs=range(len(funcs))

print('***SINGLE THREAD')
for i in nfuncs:
print('starting',funcs[i].__name__,'at:',ctime())
print(funcs[i](n))
print(funcs[i].__name__,'finished at:',ctime())

print('\n***MULTIPLE THREADS')
threads=[]
for i in nfuncs:
t=MyThread(funcs[i],(n,),funcs[i].__name__)
threads.append(t)

for i in nfuncs:
threads[i].start()

for i in nfuncs:
threads[i].join()
print(threads[i].getResult())

print('All done.')

if __name__=='__main__':
test()

结果:

>>> 
***SINGLE THREAD
starting fib at: Thu Aug 15 05:15:10 2013
233
fib finished at: Thu Aug 15 05:15:13 2013
starting fac at: Thu Aug 15 05:15:13 2013
479001600
fac finished at: Thu Aug 15 05:15:14 2013
starting sumF at: Thu Aug 15 05:15:14 2013
78
sumF finished at: Thu Aug 15 05:15:15 2013

***MULTIPLE THREADS
startingstartingstarting fibfacsumF at:at:at: Thu Aug 15 05:15:15 2013Thu Aug 15 05:15:15 2013Thu Aug 15 05:15:15 2013


facsumF finished at:finished at: Thu Aug 15 05:15:16 2013Thu Aug 15 05:15:16 2013

fib finished at: Thu Aug 15 05:15:17 2013
233
479001600
78
All done.

queue模块进行线程间通信:

import random
from time import sleep
from queue import Queue
from myThread import MyThread

def writeQ(queue):
print('producting object for Q...')
queue.put('xxx',1) #第一个参数为要写入Queue的数据,第二个参数为默认值,表示当Queue满的时候,会使线程暂停,直到空出一个位置
print('size now',queue.qsize())

def readQ(queue):
val=queue.get(1) #这个参数为默认参数,表示当Queue为空时,线程暂停,直到有了一个数据
print('consumed object from Q... size now',queue.qsize())

def writer(queue,loops):
for i in range(loops):
writeQ(queue)
sleep(random.randint(1,3))

def reader(queue,loops):
for i in range(loops):
readQ(queue)
sleep(random.randint(2,5))

funcs=[writer,reader]
nfuncs=range(len(funcs))

def test():
nloops=random.randint(2,5) #表示读与写的次数,读写次数相同
q=Queue(32)

threads=[]
for i in nfuncs:
t=MyThread(funcs[i],(q,nloops),funcs[i].__name__)
threads.append(t)

for i in nfuncs:
threads[i].start()

for i in nfuncs:
threads[i].join()

print('All done.')

if __name__=='__main__':
test()


结果:

>>> 
startingstarting writerreader at:at: Thu Aug 15 05:57:00 2013Thu Aug 15 05:57:00 2013

producting object for Q...
size nowconsumed object from Q... size now 10 #这里不是10,而是一个1,一个0.1上writeQ()输出的,0是readQ()输出的

producting object for Q...
size nowconsumed object from Q... size now 10

producting object for Q...
size now 1
writer finished at: Thu Aug 15 05:57:06 2013
consumed object from Q... size now 0
reader finished at: Thu Aug 15 05:57:10 2013
All done.