Python学习心得(七) 深入理解threading多线程模块

  Python提供了多个模块来支持多线程编程,包括thread、threading和queue模块等。
thread模块提供了基本的线程和锁定支持;而threading模块提供了更高级别、功能更全面的线程管理。
queue模块,用户可以创建一个队列数据结构,用于在多线程之间进行共享。

核心提示:避免使用thread模块
推荐使用更高级别的threading模块,原因如下:
1.threading模块更加先进,有更好的线程支持,并且thread模块中的一些属性会和threading模块有冲突;
2.低级别的thread模块拥有的同步原语很少(实际上只有一个),而threading模块则有很多;
3.thread模块对于进程何时退出没有控制,当主线程结束时,所有其他线程也都强制结束,不会发出警告或者进行适当的清理;
4.threading模块至少能确保重要的子线程在进程退出去前结束。
5.thread模块不支持守护线程这个概念(thread:当主线程退出时,所有子线程都将终止,不管它们是否仍在工作)

一.避免使用thread模块,但要了解其基本用法

import thread
from time import sleep,ctime,strftime

loops = [4,2]

def loop(nloop,nsec,lock):
    print ‘start loop‘,nloop,‘at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    sleep(nsec)
    print ‘loop‘,nloop,‘done,at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    lock.release() #释放锁
def main():
    print ‘starting at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    locks = []
    nloops = range(len(loops)) #[0, 1]
    for i in nloops:
        lock = thread.allocate_lock() #获取LockType锁对象
        lock.acquire() #取得每个锁(相当于"把锁锁上")
        locks.append(lock) #一旦锁被锁上,就可以把它添加到锁列表locks中了
        #print locks
    for i in nloops: #派生线程
        #每个线程会调用loop()函数,并传递循环号、睡眠时间以及用于该线程的锁
        thread.start_new_thread(loop,(i,loops[i],locks[i]))
        sleep(1)
    for i in nloops:
        while locks[i].locked(): #暂停主线程,等待,直到所有锁都被释放之后才会继续执行
            pass
    print ‘all done at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)

if __name__ == ‘__main__‘:
    main()

二.推荐使用更高级别的threading模块,函数式编程法  

import threading
#threading模块的Thread类有一个join()方法,可以让主线程等待所有线程执行完毕

from time import sleep,strftime

loops = [4,2,2]

def loop(nloop,nsec):
    print ‘start loop‘,nloop,‘at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    sleep(nsec)
    print ‘loop‘,nloop,‘done,at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
def main():
    print ‘starting at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    threads = []
    nloops = range(len(loops)) #[0, 1]

    for i in nloops:
        #实例化Thread(调用Thread()和之前调用thread.start_new_thread()最大区别在于新线程不会立即开始执行
        t = threading.Thread(target=loop,args=(i,loops[i])) #这是个非常有用的同步功能
        threads.append(t)

    for i in nloops: #启动线程
        #当所有线程都分配完成后,通过调用每个线程的start()方法来让它们执行,而不是在这之前就会执行
        threads[i].start()

    for i in nloops:
        #为每个线程调用join()方法,join()方法将等待线程结束,或在提供了超时时间的情况下,达到超时时间。
        threads[i].join()
        #join()方法只有在你需要等待线程完成的时候才有用
        #join()方法其实根本不需要调用,一旦线程启动,它们就会一直执行,直到给定的函数完成后退出。

    print ‘all done at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)

print loop.__name__

if __name__ == ‘__main__‘:
    main()

三.threading模块的面向对象编程法,使用可调用的类 

import threading
from time import sleep,strftime

loops = [4,2]

class ThreadFunc(object): #添加ThreadFunc类
    def __init__(self,func,args,name = ‘‘): #构造方法设定函数自身,函数参数及函数名的字符串
        self.name = name
        self.func = func
        self.args = args
    def __call__(self): #__call__特殊方法直接调用
        self.func(*self.args)

def loop(nloop,nsec):
    print ‘start loop‘,nloop,‘at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    sleep(nsec)
    print ‘loop‘,nloop,‘done at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)

def main():
    print ‘starting at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    threads = []
    nloops = range(len(loops))

    for i in nloops: #实例化Thread类对象
        t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__)) #分配线程
        threads.append(t) 

    for i in nloops:
        threads[i].start() #真正通过start()方法才启动线程

    for i in nloops:
        threads[i].join() #等待线程完成
    print ‘all done at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)   

if __name__ == ‘__main__‘:
    main()

四.threading模块面向对象扩展,派生Thread的子类,并创建子类的实例 

‘‘‘
import threading
from time import sleep,strftime

loops = [4,2]

class MyThread(threading.Thread):
    def __init__(self,func,args,name=‘‘):
        threading.Thread.__init__(self) #MyThread子类的构造方法必须先调用基类(即父类)的构造方法
        self.name = name
        self.func = func
        self.args = args

    def run(self): #之前的特殊方法__call__在这里必须要写成run()
        self.func(*self.args)

def loop(nloop,nsec):
    print ‘start loop‘,nloop,‘at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    sleep(nsec)
    print ‘loop‘,nloop,‘done at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)

def main():
    print ‘starting at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
    threads = []
    nloops = range(len(loops))
    #print nloops

    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:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)

if __name__ == ‘__main__‘:
    main()

‘‘‘

#Thread子类MyThread
#将上面的代码独立作为一个模块,把结果保存在实例属性self.res中,并创建一个新的方法getResult()来获取这个值

import threading
from time import strftime

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:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)
        self.res = self.func(*self.args)
        print self.name,‘finished at:‘,strftime(‘%Y-%m-%d %H:%M:%S‘)

  

参考资料《python核心编程》(第3版) 

 

时间: 2024-10-13 16:22:42

Python学习心得(七) 深入理解threading多线程模块的相关文章

python学习笔记七:条件&循环语句

1.print/import更多信息 print打印多个表达式,使用逗号隔开 >>> print 'Age:',42 Age: 42   #注意个结果之间有一个空格符 import:从模块导入函数 import 模块 from 模块 import 函数 from 模块 import * 如果两个模块都有open函数的时候, 1)使用下面方法使用: module1.open()... module2.open()... 2)语句末尾增加as子句 >>> import ma

Python学习心得:类与对象

教材:<简明Python教程> Python面向对象: 如shell这种面向过程的程序都是通过"操作数据的函数"或者"语句块"来设计函数. python的程序(面向对象): 类是一个"class"类型,对象是类中的一个实例. 类的属性包括了:域和方法.(即变量和函数) 属于一个对象或类的变量被称为域,一个定义在类中的函数,叫做类的方法. 类使用关键字"class"来创建.域和方法放在同一个缩进块中. 1.域有两种:

Python学习第七天课后总结

<html> ? python学习第七天课后总结: 今日内容: 一,,字符编码:其实就是人类的语言与机器的语言进行转化的一种媒介. ? 1,人类语言与机器语言对照关系的结构被称为:编码表 ? 常用编码表大致有以下几个: ? 1> ascii (ASCII) 现为今出现最早的编码表,采用一个字节来存储字母却无法编码汉字 ? 2> GBK 这个是专门为中文来制作的编码,国人专用 ? 3> Shift_JIS 日文使用的文件编码方式 ? 4> Euc-kr 韩文使用的编码方式

Python学习笔记16:标准库多线程(threading包裹)

Python主要是通过标准库threading包来实现多线程. 今天,互联网时代,所有的server您将收到大量请求. server要利用多线程的方式的优势来处理这些请求,为了改善网络port读写效率. Python它是一个网络server后台工作语言 (豆瓣网),所以多线程也就非常自然被Python语言支持. 多线程售票以及同步 我们使用Python来实现Linux多线程与同步文中的售票程序. 我们使用mutex (也就是Python中的Lock类对象) 来实现线程的同步: import th

python 学习笔记 13 -- 经常使用的时间模块之time

Python 没有包括相应日期和时间的内置类型.只是提供了3个相应的模块,能够採用多种表示管理日期和时间值: *    time 模块由底层C库提供与时间相关的函数.它包括一些函数用于获取时钟时间和处理器的执行时间,还提供了基本解析和字符串格式化工具 *    datetime 模块为日期.时间以及日期时间值提供一个更高层接口. datetime 中的类支持算术.比較和时区配置. *    calendar 模块能够创建周.月和年的格式化表示. 它还能够用来计算反复事件.给定日期是星期几,以及其

Python学习手册之__main__,常用第三方模块和打包发布

在上一篇文章中,我们介绍了 Python 的 元组拆包.三元运算符和对 Python 的 else 语句进行了深入讲解,现在我们介绍 Python 的 __main__ 模块.常用第三方模块和打包发布.查看上一篇文章请点击:https://www.cnblogs.com/dustman/p/10057482.html __main__大多数 Python 代码要么是导入的模块,要么是执行某些任务的脚本.但是,有时需要使一个文件既可以作为模块导入,也可以作为脚本运行. def sayHello()

Python学习心得——基础知识(七)

一.冒泡排序 1.要求 把列表中无序的字符按小到大排序:[9,6,15,11,36,28] 2.思路 把列表中相邻的字符值进行排序,值的放到右侧,逐个比较直到满足要求,类似水中的气泡朝水面移动. 3.样例 针对列表[9,236,1,7,5,18]按从小到大排序 1 #!usr/bin/env python 2 # -*- coding: utf-8 3 4 lis=[9,236,1,7,5,18] 5 for i in range(1,len(lis)): #判断有几次大循环数据比较 6 for

python学习第七天 -- dict 和set

今天主要学习关于python 的dict(全称dictionary)和set.dict的用法跟javascript 中map表类似,key + value结构语言.而set,准确来说,只是key的集合. Dict 直接贴代码 >>> d = {'zhangsan': 95, 'lixi': 75, 'wuliu': 85} >>> d['zhangsan'] 95 dict插入 >>>d['wangba'] = 90 //直接插入wangba该学员的成

Python学习笔记七-错误和异常

程序员总是和各种错误打交道,学习如何识别并正确的处理程序错误是很有必要的. 7.1错误和异常 1.错误 从软件方面来看,错误分为语法错误和逻辑错误两种.这两种错误都将导致程序无法正常进行下去,当Python检测到一个错误时就出现了异常. 2.异常 当编译器检测到错误并且意识到错误条件.解释器会引发一个异常(程序员也可以自己引发一个异常,后面会说到). 以下是7种Python中常见的错误. 1.NameError,尝试访问一个未申明的例子. 2.ZeroDivisionError,零除错误. 3.