• Python:线程


    Python中创建线程有两种方式:函数或者用类来创建线程对象。

    • 函数式:调用 _thread 模块中的start_new_thread()函数来产生新线程。
    • 类:创建threading.Thread的子类来包装一个线程对象。

    一.函数式:调用thread模块中的start_new_thread()函数来产生新线程

    thread.start_new_thread ( function, args[, kwargs] )
    • function - 线程函数
    • args - 传递给线程函数的参数,他必须是个tuple类型
    • kwargs - 可选参数

    例:通过thread来创建新线程

    import thread,time
    
    def timer(name,delay):
        count = 0
        while count < 5:
            time.sleep(delay)
            count +=1
            print "%s:%s" %(name,time.ctime())
    
    #创建两个线程
    thread.start_new_thread(timer,('Thread-1',2,))   #timer表示执行timer函数,后面元组内表示timer函数的两个参数
    thread.start_new_thread(timer,('Thread-2',4,))
    while 1:
        pass

     输出结果:

    Thread-1:Tue Oct 18 16:05:23 2016
    Thread-1:Tue Oct 18 16:05:25 2016
    Thread-2:Tue Oct 18 16:05:25 2016
    Thread-1:Tue Oct 18 16:05:27 2016
    Thread-1:Tue Oct 18 16:05:29 2016
    Thread-2:Tue Oct 18 16:05:29 2016
    Thread-1:Tue Oct 18 16:05:31 2016
    Thread-2:Tue Oct 18 16:05:33 2016
    Thread-2:Tue Oct 18 16:05:37 2016
    Thread-2:Tue Oct 18 16:05:41 2016

    二.类:创建threading.Thread的子类来包装一个线程对象

    例1,通过threading来创建新线程:

    import threading,time
    
    def show(arg):
        time.sleep(2)
        print 'thread' + str(arg)
    
    for i in range(10):
        t = threading.Thread(target=show,args=(i,))  #target=show执行show函数,后面args表示show函数中传入的参数
        t.start()

    运行结果:

    Main thread stop.
    Tue Oct 18 11:44:41 2016
    thread0
    thread2
    thread4
    thread3
    thread1
    thread8
    thread6
    thread5
    thread7
    thread9

     

    例2:单线程

    from time import ctime,sleep
    def Music(music):
        for i in range(2):
            print ('I am listening to the music now...%s' %ctime())
            sleep(2)
    
    def Movie(movie):
        for i in range(2):
            print('I am watching movie now...%s' %ctime())
            sleep(5)
    
    if __name__ == '__main__':
        Music('Goodbye')
        Movie('Who Am I')
        print ('Main Process is over...%s' %ctime())

    输出结果:

    I am listening to the music now...Mon Dec 12 14:53:24 2016
    I am listening to the music now...Mon Dec 12 14:53:26 2016
    I am watching movie now...Mon Dec 12 14:53:28 2016
    I am watching movie now...Mon Dec 12 14:53:33 2016
    Main Process is over...Mon Dec 12 14:53:38 2016

    例3:多线程

    import threading
    import time
    
    def Music(music):
        for i in range(2):
            print('I am listening to the <%s> now...%s' %(music,time.ctime()))
            time.sleep(2)
    
    def Movie(movie):
        for i in range(2):
            print('I am watching <%s> now...%s' %(movie,time.ctime()))
            time.sleep(5)
    
    t1 = threading.Thread(target=Music,args=('I Will',))
    t2 = threading.Thread(target=Movie,args=('The Walking Dead',))
    
    if __name__ == '__main__':
        #t1.daemon = True   #如果为True,说明该线程为守护线程,也就表明这个线程不重要,在主线程退出的时候不用等待这个线程
        #t2.daemon = True
        #如果想等待子线程执行完之后,主线程才退出,就不需要设置daemon属性(daemon属性默认就为False)
        t1.start()
        t2.start()
        #t1.join()    #停止主线程,直到执行完子线程t1后才执行主线程
        #t2.join()    #停止主线程,直到执行完子线程t2后才执行主线程
        print('all is over...%s' %time.ctime())

    输出结果:

    I am listening to the <I Will> now...Mon Dec 12 14:41:48 2016   #与另外一条子线程同时运行的,注意时间!
    I am watching <The Walking Dead> now...Mon Dec 12 14:41:48 2016
    all is over...Mon Dec 12 14:41:48 2016
    I am listening to the <I Will> now...Mon Dec 12 14:41:50 2016
    I am watching <The Walking Dead> now...Mon Dec 12 14:41:53 2016

    上面例题中如果启用t1.join和t2.join结果如下:

    I am listening to the <I Will> now...Mon Dec 12 14:42:56 2016
    I am watching <The Walking Dead> now...Mon Dec 12 14:42:56 2016
    I am listening to the <I Will> now...Mon Dec 12 14:42:58 2016
    I am watching <The Walking Dead> now...Mon Dec 12 14:43:01 2016
    all is over...Mon Dec 12 14:43:06 2016    #等待子线程运行结束后才执行主线程

     

    Threading模块中所有对象:

    1,Thread

    • start() #开始线程的执行
    • run() #定义线程的功能的函数(一般会被子类重写)
    • join(timeout=None) #程序挂起,直到该线程执行结束(如果设置了timeout,最多阻塞timeout秒)
    • getName() #返回线程名字
    • setName(name) #设置线程名字
    • isAlive() #查看该线程是否还在运行
    • isDaemon(False) #设置守护进程(True)或非守护线程(默认为False),如果设置为守护线程(True)表示该线程不重要,主线程无需等待该线程结束才退出。

    2,Lock(Rlock):只允许一个线程更改数据。提供acquire方法(获取锁)和release方法(释放锁)

    • RLock和Lock 的区别:RLock允许在同一线程中被多次acquire和release。RLock中acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。而Lock不一样,同一线程只能使用一次acquire和release方法。

    3,condition

    4,Event

    5,Semaphore(BoundedSemaphore):同时允许一定数量的线程更改数据,信号量也提供acquire方法和release方法。

    6,其他函数:

    activeCount() #返回当前活动线程的数量
    currentThread() #返回当前线程
    enumerate() #返回当前活动线程的列表
    settrace(func) #为所有线程设置一个跟踪函数
    setprofile() #为所有线程设置一个profile函数

    多线程实现同步的方法:

    1.线程锁:在同一个进程中的资源,所有线程都是共享的。线程之间是进行随机调度,如果不同线程同时对数据进行修改,就会产生问题。为了保证数据的准确性,引入了锁的概念。也就是在同一时刻只允许一个线程操作该数据。

    锁有两种状态:锁定和未锁定

    每当一个线程1要访问共享数据时,必须先获得锁定;如果已经有别的线程2获得锁定了,那么就让线程1暂停,也就是同步阻塞;等到线程2访问完毕,释放锁以后,再让线程1继续。

    使用锁方法:

    lock = threading.Lock()   #创建锁
    lock.acquire([timeout])   #锁定 
    lock.release()   #释放 

    例1:未使用锁之前:(注意同一时间点,num值的变化)

    import threading
    import time
    
    num = 0
    
    def fun(arg):
        global num
        time.sleep(1)
        num += 1
        print(num,'-->','%s'%time.ctime())
    
    for item in range(5):  #开启5个子线程
        t = threading.Thread(target=fun,args=(item,))
        t.start()
    
    print('Main threading stop !')

    输出结果:

    Main threading stop !
    1 --> Mon Dec 12 15:51:03 2016
    2 --> Mon Dec 12 15:51:03 2016
    3 --> Mon Dec 12 15:51:03 2016   #同一时间点输出的num都不一样
    4 --> Mon Dec 12 15:51:03 2016
    5 --> Mon Dec 12 15:51:03 2016

    例2:使用锁之后:

    import threading
    import time
    
    num = 0
    lock = threading.Lock()    #创建锁
    
    def fun(arg):
        lock.acquire()   #获取锁
        global num
        time.sleep(1)
        num += 1
        print(num,'-->','%s'%time.ctime())
        lock.release()   #释放锁
    
    
    for item in range(5):  #开启5个子线程
        t = threading.Thread(target=fun,args=(item,))
        t.start()
    
    print('Main threading stop !')

    输出结果:

    Main threading stop !
    1 --> Mon Dec 12 15:56:34 2016
    2 --> Mon Dec 12 15:56:35 2016
    3 --> Mon Dec 12 15:56:36 2016    #注意:同一时间点num值不变
    4 --> Mon Dec 12 15:56:37 2016
    5 --> Mon Dec 12 15:56:38 2016

    2,信号量Semaphore

    例:

    import threading
    import time
    
    se = threading.Semaphore(5)  #同时允许5个线程修改数据
    
    def fun(n):
        se.acquire()
        time.sleep(1)
        print('thread:%s -->%s'%(n,time.ctime()))
        se.release()
    
    if __name__ == '__main__':
        for i in range(10):
            t = threading.Thread(target=fun,args=(i,))
            t.start()

    输出结果:

    thread:0 -->Mon Dec 12 16:36:12 2016
    thread:1 -->Mon Dec 12 16:36:12 2016
    thread:3 -->Mon Dec 12 16:36:12 2016
    thread:2 -->Mon Dec 12 16:36:12 2016
    thread:4 -->Mon Dec 12 16:36:12 2016   #同一时间点,允许5个线程同时修改值
    thread:6 -->Mon Dec 12 16:36:13 2016
    thread:8 -->Mon Dec 12 16:36:13 2016
    thread:5 -->Mon Dec 12 16:36:13 2016
    thread:9 -->Mon Dec 12 16:36:13 2016
    thread:7 -->Mon Dec 12 16:36:13 2016

    3,时间event:通用的条件变量,多个线程可以等待某个事件发生后,所有线程都被激活。事件主要提供了三个方法 set、wait、clear。

    事件处理的机制:

    全局定义了一个“Flag”:
    (1)如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞
    (2)如果“Flag”值为True,那么event.wait 方法时便不再阻塞

    clear:将“Flag”设置为False
    set:将“Flag”设置为True

    import threading
    
    eve = threading.Event()
    
    def fun(e):
        print('start...')
        e.wait()
        print('execute...')
    
    for i in range(5):
        t = threading.Thread(target=fun,args=(eve,))
        t.start()
    
    eve.clear()
    usr_input = input('Enter the flag:')
    if usr_input =='1':
        eve.set()

    输出结果:

    start...
    start...
    start...
    start...
    start...
    Enter the flag:1
    execute...
    execute...
    execute...
    execute...
    execute...

    4,条件Condition:使线程进入等待状态,当满足某个条件时,才释放线程。

    notify()方法会唤醒一个在等待conditon变量的线程;notify_all() 则会唤醒所有在等待conditon变量的线程

    例如生产者模型:

    import threading
    import time
    c = threading.Condition()
    
    def fun(n):
        c.acquire()
        c.wait()
        print('current threading:%s ---> %s' %(n,time.ctime()))
        time.sleep(1)
        c.release()
    
    if __name__ == '__main__':
        for i in range(10):
            t = threading.Thread(target=fun,args=(i,))
            t.start()
    
        while True:
            usr_input = input('Enter:')
            if usr_input == 'q':
                break
    
            c.acquire()
            c.notify(int(usr_input))
            c.release()

    输出结果:

    Enter:3
    current threading:1 ---> Mon Dec 12 17:14:40 2016
    current threading:2 ---> Mon Dec 12 17:14:41 2016
    current threading:0 ---> Mon Dec 12 17:14:39 2016
    current threading:0 ---> Mon Dec 12 17:14:39 2016
    Enter:5
    current threading:4 ---> Mon Dec 12 17:14:47 2016
    current threading:6 ---> Mon Dec 12 17:14:48 2016
    current threading:3 ---> Mon Dec 12 17:14:49 2016
    current threading:5 ---> Mon Dec 12 17:14:50 2016
    current threading:7 ---> Mon Dec 12 17:14:51 2016
    Enter:3
    current threading:9 ---> Mon Dec 12 17:14:59 2016
    current threading:8 ---> Mon Dec 12 17:15:00 2016
    Enter:q
    
    Process finished with exit code 0

    5.定时器:指定n秒后执行某操作

    import threading
    import time
    
    print('Time:%s'%time.ctime())
    def Print():
        print('hello,python...%s'%time.ctime())
    
    t = threading.Timer(2,Print)   #2秒后执行Print函数
    t.start()

    输出结果:

    Time:Mon Dec 12 17:24:50 2016
    hello,python...Mon Dec 12 17:24:52 2016  #2秒后执行

    同步队列Queue:

    • Queue模块提供了同步队列和线程安全。包括FIFO队列、LIFO队列以及优先级队列。可以使用队列来实现线程间的同步。

        FIFO:(默认为FIFO)

    • Queue模块可以用来进行线程间通讯,让各个线程之间共享数据。
    • Queue解决了生产者,消费者的问题。

    Queue模块常用方法:

    import queue  #导入queue模块
    q = queue.Queue(maxsize=0)   #构造一个FIFO队列。maxsize指定队列的长度。为0时,表示队列长度无限制。
    
    q.put(item='n',block=1,timeout=None)   #在队尾插入一个item(必选项)。如果当前队列为空,且block为1(默认值)时,put()方法就使
    #线程暂停,一直阻塞到队列中有空间为止;如果block为0,put()方法会引发Full异常。
    
    q.get(block=1,timeout=None)   #从队首删除并返回一个项目。当block为1(默认值)时,get()方法使线程暂停,直到有项目可用。如果队列为空,且block为0时,队列将引发empty异常。
    
    q.put_nowait(item='n')   #相当于q.put(item,False)
    q.get_nowait()   #相当于q.get(False)
    q.join()  #等到队列为空时,在执行别的操作
    q.qsize()  #返回队列的大小
    q.empty()  #当队列为空时,返回True,否则返回False
    q.full()  #当队列满时,返回True,否则返回False
    q.task_done()   #在完成一项工作之后,它向任务已完成的队列发送一个信号

    例:

    from threading import Thread
    from queue import Queue
    import time
    
    class Producer(Thread):   #定义生产者类
        def __init__(self,name,queue):
            self.Name = name
            self.Queue = queue
            super(Producer,self).__init__()   #执行父类的构造函数
    
        def run(self):     #生产者具体工作内容
            while True:
                if self.Queue.full():
                    time.sleep(1)
                else:
                    self.Queue.put('产品')
                    time.sleep(1)
                    print ('%s生产一个产品' %(self.Name,))
    
                    #Thread.run(self)
    
    class Consumer(Thread):   #定义消费者类
        def __init__(self,name,queue):
            self.Name = name
            self.Queue = queue
            super(Consumer, self).__init__()   #执行父类的构造函数
        def run(self):
            while True:
                if self.Queue.empty():
                    time.sleep(1)
                else:
                    self.Queue.get('产品')
                    time.sleep(1)
                    print ('%s消费了一个产品' %(self.Name,))
                    #Thread.run(self)
    
    que = Queue(maxsize=100)   #定义容器
    
    person1 = Producer('P1',que)   #创建生产者P1
    person1.start()
    person2 = Producer('P2',que)   #创建生产者P2
    person2.start()
    person3 = Producer('P3',que)   #创建生产者P3
    person3.start()
    
    for num in range(20):   #创建消费者20人:C1,C2...C20
        name = 'C1%d' %(num,)
        item = Consumer(name,que)
        item.start()
  • 相关阅读:
    100天搞定机器学习|Day13-14 SVM的实现
    100天搞定机器学习|Day11 实现KNN
    100天搞定机器学习|Day9-12 支持向量机
    100天搞定机器学习|Day8 逻辑回归的数学原理
    100天搞定机器学习|Day7 K-NN
    100天搞定机器学习|Day4-6 逻辑回归
    宜信的105条数据库军规
    启动、配置、扩容、伸缩、存储,开普勒云平台之使用指南
    开普勒云平台:9个示例解析如何安装依赖
    钢铁B2B电商案例:供应链金融如何解决供应链金融痛点
  • 原文地址:https://www.cnblogs.com/ping-y/p/5970475.html
Copyright © 2020-2023  润新知