• python 多线程编程之_thread模块


    参考书籍:python核心编程

    _thread模块除了可以派生线程外,还提供了基本的同步数据结构,又称为锁对象(lock object,也叫原语锁、简单锁、互斥锁、互斥和二进制信号量)。

    下面是常用的线程函数:

    函数 描述
    start_new_thread(function,args,kwargs=None) 派生一个新的线程,使用给定的args和可选的kwargs来执行function
    allocate_lock() 分配LockType对象
    exit() 退出线程指令
    LockType锁对象的方法
    acquire(wait=None) 尝试获取锁对象
    locked() 如果获取了锁对象则返回True,否则返回False
    release() 释放锁

    _thread模块的核心函数是start_new_thread()。专门用来派生新的线程。

    我们对上节文章的onethr.py文件稍作修改:

    #!/usr/bin/env python
    
    import _thread
    from time import sleep,ctime
    
    def loop0():
        print('开始循环0次在:',ctime())
        sleep(4)
        print('结束循环0次在:',ctime())
    
    def loop1():
        print('开始循环1次在:',ctime())
        sleep(2)
        print('结束循环1次在:',ctime())
    
    '''    
    def main():
        print('开始于:',ctime())
        loop0()
        loop1()
        print('所有的任务都完成于:',ctime())
    ''' 
    
    def main():
        print('starting at:', ctime())
        _thread.start_new_thread(loop0, ())
        _thread.start_new_thread(loop1, ())
        sleep(6)
        print('all done at:', ctime())
        
    if __name__ =='__main__':
        main(

    执行该脚本三遍,结果:

    PS C:UsersWC> python E:Python3.6.3workspacemtsleepA.py
    starting at: Mon Mar 26 21:56:10 2018
    开始循环1次在: Mon Mar 26 21:56:10 2018
    开始循环0次在: Mon Mar 26 21:56:10 2018
    结束循环1次在: Mon Mar 26 21:56:12 2018
    结束循环0次在: Mon Mar 26 21:56:14 2018
    all done at: Mon Mar 26 21:56:16 2018
    PS C:UsersWC> python E:Python3.6.3workspacemtsleepA.py
    starting at: Mon Mar 26 22:00:43 2018
    开始循环0次在: Mon Mar 26 22:00:43 2018
    开始循环1次在: Mon Mar 26 22:00:43 2018
    结束循环1次在: Mon Mar 26 22:00:45 2018
    结束循环0次在: Mon Mar 26 22:00:47 2018
    all done at: Mon Mar 26 22:00:49 2018
    PS C:UsersWC> python E:Python3.6.3workspacemtsleepA.py
    starting at: Mon Mar 26 22:00:56 2018
    开始循环0次在: Mon Mar 26 22:00:56 2018
    开始循环1次在: Mon Mar 26 22:00:56 2018
    结束循环1次在: Mon Mar 26 22:00:58 2018
    结束循环0次在: Mon Mar 26 22:01:00 2018
    all done at: Mon Mar 26 22:01:02 2018

    由上面的代码可知,start_new_thread()必须包含两个参数,即使要执行的函数不需要参数,也要传递一个空元组。

    我们注意到:loop0还是loop1开始的顺序竟然可以是无序的;loop0和loop1是同时执行的;loop1是在loop0之前结束的;整个程序一共耗时6秒。

    我们可以说,loop0和loop1是并发执行的。

    我们在主程序(其实也就是主线程)中增加了一个sleep(6)的语句,这其实是为了避免主程序结束的时候,loop0和loop1两个线程还没有结束的问题。这也是_thread模块的一种线程同步机制。

    但是,我们要说这样使用sleep()来进行线程同步是不靠谱的,这也是_thread的一个弊端所在。

    这时,我们可以引用锁机制来实现相应的线程管理,并且同时改善单独的循环函数实现方式:

    import _thread
    from time import sleep, ctime
    #不再把4秒和2秒硬性的编码到不同的函数中,而是使用唯一的loop()函数,并把这些常量放进列表loops中
    loops=[4,2]
    #代替了之前的loop*()函数,三个参数分别代表了处于第几个循环中,睡眠时间和锁对象。每个循环执行到最后一句的时候,释放锁对象,告诉主线程该线程已完成
    def loop(nloop,sec,lock):
        print('开始循环',nloop,'在:',ctime())
        sleep(sec)
        print('循环',nloop ,'结束于:',ctime())
        lock.release()
        
    def main():
        print('开始于:',ctime())
        locks=[]
        nloops=range(len(loops))
        
        #第一个for循环中,创建了一个锁的列表,通过thread.allocate_lock()方法得到锁对象,再通过acquire()方法取到锁(相当于把锁锁上),取到之后就可以把它添加到锁列表locks中。
        for i in nloops:
            lock=_thread.allocate_lock()
            lock.acquire()
            locks.append(lock)
        #第二个for循环中,主要用于派生线程。每个线程都会调用loop()函数,并传递循环号、睡眠时间以及用于该线程的锁。  
        for i in nloops:
            _thread.start_new_thread(loop,(i,loops[i],locks[i]))
        #第三个for循环,按照顺序检查每个锁。每个线程执行完毕后,都会释放自己的锁对象。这里使用忙等待,让主线程等所有的锁都释放后才继续执行
        for i in nloops:
            while locks[i].locked():
                pass
        print('所有的任务完成于:',ctime())
        
    if __name__ =='__main__':
        main()

    执行结果:

    开始循环 1 在: Mon Mar 26 22:49:25 2018
    开始循环 0 在: Mon Mar 26 22:49:25 2018
    循环 1 结束于: Mon Mar 26 22:49:27 2018
    循环 0 结束于: Mon Mar 26 22:49:29 2018
    所有的任务完成于: Mon Mar 26 22:49:29 2018

    上述结果除了表名两次循环是并发执行的之外,整个程序一共用时4秒,而不是之前的6秒。

  • 相关阅读:
    EventBus (四) Sticky事件
    EventBus (三) 源码解析 带你深入理解EventBus
    EventBus (二) 使用详解——EventBus使用进阶
    EventBus (一) 使用详解——初步使用EventBus
    Android布局优化之ViewStub、include、merge使用与源码分析
    Android API 中文(14) —— ViewStub
    ViewStub用法
    FaceBook推出的Android图片加载库-Fresco
    WinForm打印之页边距
    带参数的多线程的方式
  • 原文地址:https://www.cnblogs.com/hiwuchong/p/8654662.html
Copyright © 2020-2023  润新知