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

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

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

    给出下面程序代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#!/usr/bin/env python

 

import threading

import time

 

def sayHi(n):

    time.sleep(1)

    print 'Hi this is thread %s' %n

 

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

 

for in range(20):

    thread_list.append(threading.Thread(target=sayHi, args=(i,)))

 

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

    i.start()

 

for 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'

    程序执行结果如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

xpleaf@xpleaf-machine:/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

    将程序代码修改为如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#!/usr/bin/env python

 

import threading

import time

 

def sayHi(n):

    time.sleep(1)

    print 'Hi this is thread %s' %n

 

thread_list = []

 

for in range(20):

    thread_list.append(threading.Thread(target=sayHi, args=(i,)))

 

for in thread_list:

    i.start()

 

#for in thread_list:

#   i.join()

 

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

    程序执行结果如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

xpleaf@xpleaf-machine:/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()的解释说明,这里只需要再看下面一个例子就更加好理解了。

    程序代码如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#!/usr/bin/env python

 

import threading

import time

 

def sayHi(n):

    time.sleep(2)

    print 'Hi this is thread %s' %n

 

thread_list = []

 

for in range(10):

    thread_list.append(threading.Thread(target=sayHi, args=(i,)))

 

for in thread_list:

    i.start()

 

for in thread_list:

    print i.join(0.1)

 

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

    程序执行结果如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

xpleaf@xpleaf-machine:/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-31 06:55:16

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

【Python之旅】第二篇(二):列表与元组

说明:     Python中的列表类似于其它高级语言中的数组,不过Python的列表操作起来要轻松很多.     Python中列表的学习主线主要是围绕对列表参数的操作使用上,重点关注的应该有如下这些: 1 2 3 4 5 6 7 8 9 names.append( names.count( names.extend( names.index( names.insert( names.pop( names.remove( names.reverse( names.sort(     下面的内容

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

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

【Python之旅】第一篇:基于文件处理的登陆接口

1.基本需求     编写登陆接口,实现如下需求: (1)输入用户名密码 (2)认证成功后显示欢迎信息 (3)输错三次后锁定 2.实现细节 ·每添加一个用户,需要手动添加三个文件 文件 功能 username_count.txt 记录用户输错密码的次数,最大为3次,如果用户密码输入正确,则重置为0,默认为0 username_lock.txt 记录用户是否被锁定,1表示锁定,0表示未锁定,默认为0 username_passwd.txt 记录用户的密码 ·注:username是指该用户的用户名,

【Python之旅】第二篇(一):Python文件处理

说明:     主要是file()和open()函数的使用,但在查open()函数的帮助时,会有下面的说明: 1 2 3 >>> help(open) -- Open a file using the file() type, returns a file object.     因此,两个函数其实都是一样的,下面只用file().     在列举file()的作用时,使用help即是很好的方法,下面则是应重点关注的内容: 1 2 3 4 5 6 7 8 9 10 11 12 13 14

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

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

【Python之旅】第二篇(五):基于列表、字典和元组的员工信息处理接口

1.基本需求     编写一个查询员工信息表的程序,实现如下功能: (1)让用户输入不小于3个字符查询员工信息 (2)通过员工号或员工个人信息可以精确或模糊查询到员工信息 (3)输出员工信息 2.实现代码与注释    首先提供员工信息的txt文件: 1 2 3 4 xpleaf@xpleaf-machine:/mnt/hgfs/Python/day3$ more student_info.txt  stu1101 mingjia.xu 275896019@qq.com 263 SystemAdm

【Python之旅】第二篇(四):字典

说明:     显然Python中字典的学习过程与列表是一样的,主要是围绕下面的函数来进行重点学习: 1 2 3 4 5 6 7 8 9 10 11 >>> xpleaf. xpleaf.clear( xpleaf.copy( xpleaf.get( xpleaf.has_key( xpleaf.items( xpleaf.keys( xpleaf.pop( xpleaf.popitem( xpleaf.setdefault( xpleaf.update( 1.基本操作 --创建一个字典

【Python之旅】第二篇(九):迭代器

说明:关于Python中迭代器的解释     Iterator是迭代器的意思,它的作用是一次产生一个数据项,直到没有为止.这样在 for 循环中就可以对它进行循环处理了.那么它与一般的序列类型(list, tuple等)有什么区别呢?它一次只返回一个数据项,占用更少的内存.但它需要记住当前的状态,以便返回下一数据项.它是一个有着next()方法的对象.而序列类型则保存了所有的数据项,它们的访问是通过索引进行的.     举个前面的例子来说就像readlines和xreadlines的区别,rea

【Python之旅】第二篇(六):enumerate枚举

1.普通情况下打印列表中索引号及其对应元素     使用下面的循环: 1 2 3 4 5 6 7 8 >>> L = ['a', 'b', 'c', 'd'] >>> for i in L: ...   print L.index(i),i ...  0 a 1 b 2 c 3 d 2.使用enumerate在循环时同时访问索引     可以使用enumerate实现上面的功能: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18