【Python之旅】第七篇(一):再谈Python多线程

主要是再进一步加深Python中关于多线程相关函数join()的理解以解多线程的执行过程。这里通过下面的例子来作进一步的说明。

1.多线程与主程序代码的执行顺序关系

给出下面程序代码:

#!/usr/bin/env python

import threading
import time

def sayHi(n):
	time.sleep(1)
	print ‘Hi this is thread %s‘ %n

thread_list = []    #用来存放多线程执行返回的函数入口,因此这里存放的是函数入口

for i in range(20):
	thread_list.append(threading.Thread(target=sayHi, args=(i,)))

for i in thread_list:    #执行列表中存放的函数入口,只有执行了之后才会执行sayHi()的程序代码,否则上面只是把函数入口存放在这个列表中而已
	i.start()

for i in thread_list:    #检测对应的线程是否已经执行完毕(即函数入口是否已经被执行,从而执行相关的程序代码)
	i.join()    #join()中可以加超时时间,如i.join(3),表示当前i对应的函数入口所执行的
	线程,如果在3秒内还没有执行完就超时,在线程可以正常执行的时候不加也是没有关系的,
	但是当线程出现异常而无法正常执行时,由于i.join()还没有检测到线程已经执行完毕,所
	以会一直处于等待状态,这样的话就会造成程序的代码不能继续执行(程序还停留在i.join(
	)这里等待这一个其对应的线程执行完毕),设定超时时间就可以避免这一个问题,下面会有相关说明

print ‘\033[32;1mThis is the last line\033[0m‘

程序执行结果如下:

[email protected]:/mnt/hgfs/Python/day7$ python day6thread1.py 
Hi this is thread 0
Hi this is thread 1
Hi this is thread 2
Hi this is thread 3
Hi this is thread 4
Hi this is thread 5
Hi this is thread 6
Hi this is thread 7
Hi this is thread 8
Hi this is thread 9
 Hi this is thread 11
 Hi this is thread 14
 Hi this is thread 17
 Hi this is thread 12
Hi this is thread 15
Hi this is thread 16
Hi this is thread 10
Hi this is thread 13
Hi this is thread 18
Hi this is thread 19
This is the last line

将程序代码修改为如下:

#!/usr/bin/env python

import threading
import time

def sayHi(n):
	time.sleep(1)
	print ‘Hi this is thread %s‘ %n

thread_list = []

for i in range(20):
	thread_list.append(threading.Thread(target=sayHi, args=(i,)))

for i in thread_list:
	i.start()

#for i in thread_list:
#	i.join()

print ‘\033[32;1mThis is the last line\033[0m‘

程序执行结果如下:

[email protected]:/mnt/hgfs/Python/day7$ python day6thread1.py 
This is the last line
Hi this is thread 0
 Hi this is thread 2
 Hi this is thread 6
 Hi this is thread 9
 Hi this is thread 10
 Hi this is thread 15
 Hi this is thread 16
 Hi this is thread 3
Hi this is thread 8
Hi this is thread 11
 Hi this is thread 14
Hi this is thread 17
Hi this is thread 5
Hi this is thread 13
Hi this is thread 4
Hi this is thread 1
Hi this is thread 7
Hi this is thread 12
Hi this is thread 18
Hi this is thread 19

对比两个例子可以发现,不同之处在于“This is the last line”的输出位置,未修改代码前是在最后,而修改代码后则在最前,作如下解释:

第一个例子由于加了join()作检测,程序的代码会停在i.join()的代码块中,而这里又没有设置超时时间,因此会直到检测到所有的进程都执行完毕才开始执行该代码块后面的程序代码,因此,“This is the last line”会在最后面输出;

第二个例子没有加join()作检测,所以不管线程是否已经执行完毕,只要把所有函数入口加入线程中开始执行,就马上执行i.start()代码块后面的程序代码,由于多线程执行的函数加了sleep(1),所以线程执行的输出肯定比后面打印“This is the last line”要慢,因此,这一句会在最前面输出。

多线程是这样,多进程也是类似的,前面已经有详细的例子和说明。

2.有关于join()的进一步解释说明

其实在第一个例子的程序代码中已经给出了join()的解释说明,这里只需要再看下面一个例子就更加好理解了。

程序代码如下:

#!/usr/bin/env python

import threading
import time

def sayHi(n):
	time.sleep(2)
	print ‘Hi this is thread %s‘ %n

thread_list = []

for i in range(10):
	thread_list.append(threading.Thread(target=sayHi, args=(i,)))

for i in thread_list:
	i.start()

for i in thread_list:
	print i.join(0.1)

print ‘\033[32;1mThis is the last line\033[0m‘

程序执行结果如下:

[email protected]:/mnt/hgfs/Python/day7$ time python day6thread1.py 
None
None
None
None
None
None
None
None
None
None
This is the last line
Hi this is thread 0
Hi this is thread 1
Hi this is thread 2
Hi this is thread 3
Hi this is thread 4
Hi this is thread 5
 Hi this is thread 7
 Hi this is thread 8
Hi this is thread 6
Hi this is thread 9

real	0m2.080s
user	0m0.048s
sys	0m0.016s

作如下解释说明:

1)程序代码到了i.join()时,由于0.1秒超时,而线程执行函数sleep2秒;

2)0.1秒过去后,第一个线程超时,i.join()检测第二个线程,打印输出None;

3)0.1秒过去后,第二个线程超时,i.join()检测第三个线程,打印输出None;

……

4)检测完10个线程,用了1秒,此时join()的工作完成(总共输出了10个None),执行join()后面的代码块;

5)join()后面的代码块输出“This is the last line”;

6)再过1秒后,所有线程sleep完,总共输出10句“Hi this is thread ”;

7)程序执行完毕,进程结束。

通过上面这一个例子的分析,相信无论是对多线程的执行过程,还是对join()函数的理解,都会有更进一步的认识。

时间: 2024-10-12 14:32:45

【Python之旅】第七篇(一):再谈Python多线程的相关文章

Python之旅(七)面向对象

三大编程范式 三大编程范式(这三者各有千秋,不分好坏): 面向过程编程 函数式编程 面向对象编程 面向过程编程 “面向过程”(Procedure Oriented)是一种以过程为中心的编程思想. 过程是指解决问题的步骤.例如问题:如何把大象放入一个冰箱?步骤:先打开冰箱,在将大象放入冰箱,最后关上冰箱.面向过程是一种较机械式的思维方式. 优点: 复杂的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单). 性能比面向对象高,因为类调用时需要实例化,比较消耗

Python之路【第一篇】:初识Python

Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承. 最新的TIOBE排行榜,Python赶超PHP占据第五!!! 由上图可见,Python整体呈上升趋势,反映出Python应用越来越广泛并且也逐渐得到业内的认可!!! Python可以应用于众多领域,如:数据分析.组件集成.网络服务.图像处理.数值计算和科学计算等众

Python 快速教程(补充篇04): Python简史

Python的起源 Python的作者,Guido von Rossum,确实是荷兰人.1982年,Guido从阿姆斯特丹大学(University of Amsterdam)获得了数学和计算机硕士学位.然而,尽管他算得上是一位数学家,但他更加享受计算机带来的乐趣.用他的话说,尽管拥有数学和计算机双料资质,他总趋向于做计算机相关的工作,并热衷于做任何和编程相关的活儿. Guido von Rossum 在那个时候,他接触并使用过诸如Pascal.C. Fortran等语言.这些语言的基本设计原则

Python 快速教程(补充篇02): Python小技巧

import模块 在Python经常使用import声明,以使用其他模块(也就是其它.py文件)中定义的对象. 1) 使用__name__ 当我们编写Python库模块的时候,我们往往运行一些测试语句.当这个程序作为库被import的时候,我们并不需要运行这些测试语句.一种解决方法是在import之前,将模块中的测试语句注释掉.Python有一种更优美的解决方法,就是使用__name__. 下面是一个简单的库程序TestLib.py.当直接运行TestLib.py时,__name__为”__ma

【Python之旅】第二篇(七):集合

说明: ·类似于数学中学的集合,Python中的集合可以实现去重的功能,通过set()函数来实现: ·sets支持x in set, len(set)和 for x in set: ·作为一个无序的集合,sets 不记录元素位置或者插入点,因此,sets不支持indexing, slicing,或其它类序列(sequence-like)的操作: ·学习集合,主要是学习集合的一系列标准操作:集合创建.集合添加.集合删除.交并差集等: 1.创建集合:set() >>> a = range(1

Python开发【第七篇】:面向对象

Python之路[第五篇]:面向对象及相关 面向对象基础 基础内容介绍详见一下两篇博文: 面向对象初级篇 面向对象进阶篇 其他相关 一.isinstance(obj, cls) 检查是否obj是否是类 cls 的对象 ? 1 2 3 4 5 6 class Foo(object):     pass obj = Foo() isinstance(obj, Foo) 二.issubclass(sub, super) 检查sub类是否是 super 类的派生类 ? 1 2 3 4 5 6 7 cla

python之旅【第二篇】

1,文件操作 找到文件-----打开文件------文件操作-----------文件关闭 file_open = file(文件路径,模式) 读取文件: M.read() obj = M.readlines()--------- #一行行读取,并且obj为一个列表 关于读取模式: Table mode 模式 描述 r 以读方式打开文件,可读取文件信息. w 以写方式打开文件,可向文件写入信息.如文件存在,则清空该文件,再写入新内容 a 以追加模式打开文件(即一打开文件,文件指针自动移到文件末尾

【Python之旅】第二篇(三):基于列表处理的购物清单程序

1.基本需求 编写一个购物小程序,要求实现如下功能: (1)让用户输入工资: (2)输出购物菜单及产品价格: (3)计算用户是否可支付: (4)输出用户剩余的钱,问用户是否继续购物,如果选择继续,则继续进行,否则退出程序: (5)若钱不够,输出用户还需要工作多久才能买得起(这里暂不实现此功能). 2.实现基本思路 基本思路可如下所示: 在编写程序的时候即以该思路为主线,具体细节下面再提及. 3.实现细节 基于友好用户界面的原则,实现的细节可总结如下: (1)用户输入工资时,如果输入的是非数字或没

Python自动化 【第七篇】:Python基础-面向对象高级语法、异常处理、Scoket开发基础

本节内容: 1.     面向对象高级语法部分 1.1   静态方法.类方法.属性方法 1.2   类的特殊方法 1.3   反射 2.     异常处理 3.     Socket开发基础 1.     面向对象高级语法部分 1.1   静态方法.类方法.属性方法 1)   静态方法 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法.普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访