python多线程编程

python提供了几个用于多线程编程的模块,thread,threading,Queue等。其中thread模块提供了基本的线程和锁的支持,threading提供了更高级别的功能,Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。
因为thread有下面几个缺点,所以建议使用threading模块:
1.threading更为先进
2.thread模块的同步原语很少
3.当主线程结束时所有的线程都会被强制结束,没有警告也没有正常的清理工作
4.不支持守护线程,也就是不能设置线程为daemon
所以下面重点介绍threading的三种创建进程的方法。

  1. 创建一个Thread实例,传给他一个函数
import threading
from time import ctime,sleep

loops=[4,2]
def loop(nloop,nsecond):
    print('start loop ',nloop,'at: ',ctime())
    sleep(nsecond)
    print('loop ',nloop,' done at: ',ctime())
def main():
    print('starting at: ',ctime())
    threads=[]
    nloops=range(len(loops))

    for i in nloops:
        #'target','args' are must
        threads.append(threading.Thread(target=loop,args=(i,loops[i])))
    for i in nloops:
        threads[i].start()

    for i in nloops:
        threads[i].join()
    print('all DONE at: ',ctime())
if __name__=='__main__':
    main()
  1. 创建一个Thread实例,传给他一个可调用的类对象

其中这个类对象要是可调用的对象,也就是实现了call函数的类

import threading
from time import ctime,sleep

loops=[4,2]

class ThreadFunc():
    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,nsecond):
    print('start loop ',nloop,'at: ',ctime())
    sleep(nsecond)
    print('loop ',nloop,' done at: ',ctime())
def main():
    print('starting at: ',ctime())
    threads=[]
    nloops=range(len(loops))

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

    for i in nloops:
        threads[i].join()
    print('all DONE at: ',ctime())
if __name__=='__main__':
    main()

3.从Thread派生出一个子类,创建一个子类的实例
(1)这个子类的构造器要先调用基类的构造器;(2)子类要实现run函数

import threading
from time import ctime,sleep

class MyThread(threading.Thread):
    def __init__(self,func,args,name=""):
        threading.Thread.__init__(self)
        self.name=name
        self.func=func
        self.args=args
        self.res=0
    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())
def Fib(n):
    sleep(0.005)
    if n<2:return 1
    return Fib(n-1)+Fib(n-2)
def Fac(n):
    sleep(0.1)
    if n<2:return 1
    return n*Fac(n-1)
def Sum(n):
    sleep(0.1)
    if n<1:return 0
    return n+Sum(n-1)

func=[Fib,Fac,Sum]
n=12
def main():
    threads=[]
    nfunc=range(len(func))

    print('***MULTIPE THREAD')
    for i in nfunc:
       threads.append(MyThread(func[i],(n,),func[i].__name__))

    for i in nfunc:
        threads[i].start()
    for i in nfunc:
        threads[i].join()
        print(threads[i].getResult())
    print('all DONE')
if __name__=='__main__':
    main()

下面是queue模块,它提供了三个类,Queue,LifoQueue,PriorityQueue
具体详见:Python queue模块
其中的两个方法:
put(item,block=0)如果block不等于0,函数会一直阻塞下去到队列中有空间为止
get(block=0)block的作用同put

import threading
from time import ctime,sleep
from queue import Queue
from random import randint


class MyThread(threading.Thread):
    def __init__(self,func,args,name=""):
        threading.Thread.__init__(self)
        self.name=name
        self.func=func
        self.args=args
        self.res=0
    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())

def writeQ(queue):
    print('producting object for Q...')
    queue.put('xxx',1)
    print('size now',queue.qsize())

def readQ(queue):
    val=queue.get(1)
    print('consumed object from Q...size now',queue.qsize())
def writer(queue,loops):
    for i in range(loops):
        writeQ(queue)
        sleep(randint(1,3))
def reader(queue,loops):
    for i in range(loops):
        readQ(queue)
        sleep(randint(2,5))

func=[writer,reader]
n=12
def main():
    threads=[]
    nfunc=range(len(func))
    q=Queue(32)
    nloops=randint(2,5)

    print('***MULTIPE THREAD')
    for i in nfunc:
       threads.append(MyThread(func[i],(q,nloops),func[i].__name__))

    for i in nfunc:
        threads[i].start()
    for i in nfunc:
        threads[i].join()
    print('all DONE')
if __name__=='__main__':
    main()

然后简单的介绍一下threading中的另外三个类Lock,Condition,Event。
Lock:
其实很简单就是加锁控制资源访问

import threading
import time

class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)

        if mutex.acquire(1): 
            num = num+1
            msg = self.name+' set num to '+str(num)
            print(msg)
            mutex.release()
num = 0
mutex = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()

Evevt类:
多个线程等待某个事件发生,发生后,所有的线程被激活
Event对象实现了简单的线程通信机制,它提供了设置信号,清楚信号,等待等用于实现线程间的通信。
1 设置信号
使用Event的set()方法可以设置Event对象内部的信号标志为真。Event对象提供了isSet()方法来判断其内部信号标志的状态。当使用event对象的set()方法后,isSet()方法返回真
2 清除信号
使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设为假,当使用Event的clear方法后,isSet()方法返回假
3 等待
Event对象wait的方法只有在内部信号为真的时候才会很快的执行并完成返回。当Event对象的内部信号标志位假时,则wait方法一直等待到其为真时才返回。

import threading
class mythread(threading.Thread):
    def __init__(self,threadname):
        threading.Thread.__init__(self,name=threadname)
    def run(self):
        global event
        if event.isSet():
            event.clear()
            event.wait()
            print(self.getName())
        else:
            print(self.getName())
            event.set()
event=threading.Event()
event.set()
t1=[]
for i in range(10):
    t=mythread(str(i))
    t1.append(t)
for i in t1:
    i.start()

Condition类:
使用Condition对象可以在某些事件触发或者达到特定的条件后才处理数据,Condition除了具有Lock对象的acquire方法和release方法外,还有wait方法、notify方法、notifyAll方法等用于条件处理。

threading.Condition([lock]):创建一个condition,支持从外界引用一个Lock对象(适用于多个condtion共用一个Lock的情况),默认是创建一个新的Lock对象。

acquire()/release():获得/释放 Lock

wait([timeout]):线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。调用wait()会释放Lock,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得Lock.

notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。

notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少)

import threading 
import time 

condition = threading.Condition() 
products = 0 

class Producer(threading.Thread): 
    def __init__(self): 
        threading.Thread.__init__(self) 

    def run(self): 
        global condition, products 
        while True: 
            if condition.acquire(): 
                if products < 10: 
                    products += 1; 
                    print("Producer(%s):deliver one, now products:%s" %(self.name, products))
                    condition.notify() 
                else: 
                    print("Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products))
                    condition.wait(); 
                condition.release() 
                time.sleep(2) 

class Consumer(threading.Thread): 
    def __init__(self): 
        threading.Thread.__init__(self) 

    def run(self): 
        global condition, products 
        while True: 
            if condition.acquire(): 
                if products > 1: 
                    products -= 1 
                    print("Consumer(%s):consume one, now products:%s" %(self.name, products))
                    condition.notify() 
                else: 
                    print("Consumer(%s):only 1, stop consume, products:%s" %(self.name, products))
                    condition.wait(); 
                condition.release() 
                time.sleep(2) 

if __name__ == "__main__": 
    for p in range(0, 2): 
        p = Producer() 
        p.start() 
    for c in range(0, 10): 
        c = Consumer() 
        c.start()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值