18 多线程编程 - 《Python 核心编程》

?? 引言/动机

?? 线程和进程

?? 线程和 Python

?? thread 模块

?? threading 模块

?? 生产者-消费者问题和 Queue 模块

?? 相关模块

18.1 引言/动机

18.2 线程和进程

什么是进程?

计算机程序只不过是磁盘中可执行的,二进制(或其它类型)的数据。它们只有在被读取到内

存中,被操作系统调用的时候才开始它们的生命期。进程(有时被称为重量级进程)是程序的一次

执行。每个进程都有自己的地址空间,内存,数据栈以及其它记录其运行轨迹的辅助数据。操作系

统管理在其上运行的所有进程,并为这些进程公平地分配时间。进程也可以通过fork 和spawn 操作

来完成其它的任务。不过各个进程有自己的内存空间,数据栈等,所以只能使用进程间通讯(IPC),

而不能直接共享信息。

什么是线程?

线程(有时被称为轻量级进程)跟进程有些相似,不同的是,所有的线程运行在同一个进程中, 共享相同的运行环境。

线程有开始,顺序执行和结束三部分。它有一个自己的指令指针,记录自己运行到什么地方。

线程的运行可能被抢占(中断),或暂时的被挂起(也叫睡眠),让其它的线程运行,这叫做让步。

一个进程中的各个线程之间共享同一片数据空间,所以线程之间可以比进程之间更方便地共享数据

以及相互通讯。线程一般都是并发执行的,正是由于这种并行和数据共享的机制使得多个任务的合

作变为可能。实际上,在单CPU 的系统中,真正的并发是不可能的,每个线程会被安排成每次只运

行一小会,然后就把CPU 让出来,让其它的线程去运行。在进程的整个运行过程中,每个线程都只

做自己的事,在需要的时候跟其它的线程共享运行的结果。

如果多个线程共同访问同一片数据,则由于数据访 问的顺序不一样,有可能导致数据结果的不一致

的问题。这叫做竞态条件(race condition)。幸运的是,大多数线程库都带有一系列的同步原语,来

控制线程的执行和数据的访问。

18.3 Python、线程和全局解释器锁

全局解释器锁(GIL)

Python 代码的执行由Python 虚拟机(也叫解释器主循环)来控制。Python 在设计之初就考虑到

要在主循环中,同时只有一个线程在执行,就像单CPU 的系统中运行多个进程那样,内存中可以存

放多个程序,但任意时刻,只有一个程序在CPU 中运行。同样地,虽然Python 解释器中可以“运行”

多个线程,但在任意时刻,只有一个线程在解释器中运行。

对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个

线程在运行。在多线程环境中,Python 虚拟机按以下方式执行:

在调用外部代码(如C/C++扩展函数)的时候,GIL 将会被锁定,直到这个函数结束为止(由于

在这期间没有Python 的字节码被运行,所以不会做线程切换)。编写扩展的程序员可以主动解锁GIL。

不过,Python 的开发人员则不用担心在这些情况下你的Python 代码会被锁住。

退出线程

当一个线程结束计算,它就退出了。线程可以调用thread.exit()之类的退出函数,也可以使用

Python 退出进程的标准方法,如sys.exit()或抛出一个SystemExit 异常等。不过,你不可以直接

“杀掉”("kill")一个线程。

在Python 中使用线程

在Win32 和Linux, Solaris, MacOS, *BSD 等大多数类Unix 系统上运行时,Python 支持多线程编程。

Python 使用POSIX 兼容的线程,即pthreads。

默认情况下,从源代码编译的(2.0 及以上版本的)Python 以及Win32 的安装包里,线程支持是打开的。

没有线程支持的情况

 1 #!/usr/bin/env python
 2
 3 from time import sleep, ctime
 4
 5 def loop0():
 6     print ‘start loop 0 at:‘, ctime()
 7     sleep(4)
 8     print ‘loop 0 done at:‘, ctime()
 9
10 def loop1():
11     print ‘start loop 1 at:‘, ctime()
12     sleep(2)
13     print ‘loop 1 done at:‘, ctime()
14
15 def main():
16     print ‘starting at:‘, ctime()
17     loop0()
18     loop1()
19     print ‘all DONE at:‘, ctime()
20
21 if __name__ == ‘__main__‘:
22     main()

onethr.py

Python 的threading 模块

Python 提供了几个用于多线程编程的模块,包括thread, threading 和Queue 等。thread 和

threading 模块允许程序员创建和管理线程。thread 模块提供了基本的线程和锁的支持,而threading

提供了更高级别,功能更强的线程管理的功能。Queue 模块允许用户创建一个可以用于多个线程之间

共享数据的队列数据结构。我们将分别介绍这几个模块,并给出一些例子和中等大小的应用。

核心提示:避免使用thread 模块

首先,更高级别的threading 模块更为先进,对线程的支持更为完善,而且使用thread 模块里的属性有可能会与threading 出现冲突。

其次, 低级别的thread 模块的同步原语很少(实际上只有一个),而threading 模块则有很多。

最后,对于你的进程什么时候应该结束完全没有控制,当主线程结束时,所有的线程都会被强制结束掉,没有警告也不会有正常的清除工作。

只建议那些有经验的专家在想访问线程的底层结构的时候,才使用thread 模块。

18.4 thread 模块

使用thread 模块 (mtsleep1.py)

 1 #!/usr/bin/env python
 2
 3 import thread
 4 from time import sleep, ctime
 5
 6 def loop0():
 7     print ‘start loop 0 at:‘, ctime()
 8     sleep(4)
 9     print ‘loop 0 done at:‘, ctime()
10
11 def loop1():
12     print ‘start loop 1 at:‘, ctime()
13     sleep(2)
14     print ‘loop 1 done at:‘, ctime()
15
16 def main():
17     print ‘starting at:‘, ctime()
18     thread.start_new_thread(loop0, ())
19     thread.start_new_thread(loop1, ())
20     sleep(6)
21     print ‘all DONE at:‘, ctime()
22
23 if __name__ == ‘__main__‘:
24     main()

mtsleep1.py

使用线程和锁 (mtsleep2.py)

 1 #!/usr/bin/env python
 2
 3 import thread
 4 from time import sleep, ctime
 5
 6 loops = [4,2]
 7
 8 def loop(nloop, nsec, lock):
 9     print ‘start loop‘, nloop, ‘at:‘, ctime()
10     sleep(nsec)
11     print ‘loop‘, nloop, ‘done at:‘, ctime()
12     lock.release()
13
14 def main():
15     print ‘starting at:‘, ctime()
16     locks = []
17     nloops = range(len(loops))
18
19     for i in nloops:
20         lock = thread.allocate_lock()
21         lock.acquire()
22         locks.append(lock)
23
24     for i in nloops:
25         thread.start_new_thread(loop, (i, loops[i], locks[i]))
26
27     for i in nloops:
28         while locks[i].locked(): pass
29
30     print ‘all DONE at:‘, ctime()
31
32 if __name__ == ‘__main__‘:
33     main()

mtsleep2.py

18.5 threading 模块

Thread 类

threading 的Thread 类是你主要的运行对象。它有很多thread 模块里没有的函数。

用Thread 类,你可以用多种方法来创建线程。

创建一个Thread 的实例,传给它一个函数

 1 #!/usr/bin/env python
 2
 3 import threading
 4 from time import sleep, ctime
 5
 6 loops = [4,2]
 7
 8 def loop(nloop, nsec):
 9     print ‘start loop‘, nloop, ‘at:‘, ctime()
10     sleep(nsec)
11     print ‘loop‘, nloop, ‘done at:‘, ctime()
12
13 def main():
14     print ‘starting at:‘, ctime()
15     threads = []
16     nloops = range(len(loops))
17
18     for i in nloops:
19         t = threading.Thread(target=loop,20                 args=(i, loops[i]))
21         threads.append(t)
22
23     for i in nloops: # start threads
24         threads[i].start()
25
26     for i in nloops:
27         threads[i].join() # threads to finish
28
29     print ‘all DONE at:‘, ctime()
30
31 if __name__ == ‘__main__‘:
32     main()

mtsleep3.py

创建一个Thread 的实例,传给它一个可调用的类对象

从Thread 派生出一个子类,创建一个这个子类的实例

 1 #!user/env/bin python
 2
 3 import threading
 4 from time import sleep, ctime
 5
 6 loops = [4,2]
 7
 8 class Thread4(threading.Thread):
 9     def __init__(self, nloop, nsec, 10             group=None, target=None, name=None,11             args=(), kwargs=None, verbose=None):
12         self.nloop = nloop
13         self.nsec = nsec
14         threading.Thread.__init__(self)
15     def run(self):
16         print ‘start loop‘, self.nloop, ‘at:‘, ctime()
17         sleep(self.nsec)
18         print ‘loop‘, self.nloop, ‘done at:‘, ctime()
19
20 def main():
21     print ‘starting at:‘, ctime()
22     threads = list()
23     nloops = range(len(loops))
24
25     for i in nloops:
26         t = Thread4(i, loops[i])
27         threads.append(t)
28
29     for i in nloops:
30         threads[i].start()
31
32     for i in nloops:
33         threads[i].join()
34
35     print ‘all DONE at:‘, ctime()
36
37 if __name__ == ‘__main__‘:
38     main()

mtsleep5.py

 1 #!usr/bin/env python
 2
 3 from myThread import MyThread
 4 from time import time
 5
 6 def fabonacci(n):
 7         if n <= 2:
 8                 return 1
 9         if n > 2:
10                 return fabonacci(n-1) + fabonacci(n-2)
11
12 def factorial(n):
13         if n <= 1:
14                 return 1
15         if n > 1:
16                 return factorial(n-1) * n
17
18 def count(n):
19         sum = 0
20         for i in range(n+1):
21                 sum += i
22         return sum
23
24 def main():
25         t1 = time()
26         threads = list()
27         loops = [32,10,100000]
28
29         threads.append(MyThread(fabonacci, (loops[0],)))
30         threads.append(MyThread(factorial, (loops[1],)))
31         threads.append(MyThread(count, (loops[2],)))
32
33         for t in threads:
34                 t.start()
35
36         for t in threads:
37                 t.join()
38
39         for t in threads:
40                 print t.func.__name__, ‘(%d)=‘ % t.args[0],41                                 t.getResult(), ‘time:%f‘ % t.getts()
42         t2 = time()
43         print ‘All time:%f‘ % (t2-t1)
44
45         t1 = time()
46         fabonacci(loops[0])
47         factorial(loops[1])
48         count(loops[2])
49         t2 = time()
50         print ‘%f‘ % (t2-t1)
51
52
53 if __name__ == ‘__main__‘:
54         main()
55         

mtfabonacci.py

 1 #!usr/bin/env python
 2
 3 import threading
 4 from time import time
 5
 6 class MyThread(threading.Thread):
 7     def __init__(self, func, args):
 8         self.func = func
 9         self.args = args
10         self.res = None
11         self.ts = 0
12         threading.Thread.__init__(self)
13
14     def run(self):
15         t1 = time()
16         self.res = apply(self.func, self.args)
17         t2 = time()
18         self.ts = t2 - t1
19
20     def getResult(self):
21         return self.res
22
23     def getts(self):
24         return self.ts

myThread.py

threading 模块中的其它函数

生产者-消费者问题和Queue 模块

Queue 模块可以用来进行线程间通讯,让各个线程之间共享数据。

 1 #!/usr/bin/env python
 2
 3 from random import randint
 4 from time import sleep
 5 from Queue import Queue
 6 from myThread import MyThread
 7
 8 def writeQ(queue):
 9     print ‘producting object for Q...‘
10     queue.put(‘product‘, 1)
11     print "size now %d" % queue.qsize()
12
13 def readQ(queue):
14     val = queue.get(1)
15     print ‘consumed object from Q... size now, %d‘ %16             queue.qsize()
17
18 def writer(queue, loops):
19     for i in range(loops):
20         writeQ(queue)
21         sleep(randint(1, 3))
22
23 def reader(queue, loops):
24     for i in range(loops):
25         readQ(queue)
26         sleep(randint(2, 5))
27
28 funcs = [writer, reader]
29 nfuncs = range(len(funcs))
30
31 def main():
32     nloops = randint(2, 5)
33     q = Queue(32)
34
35     threads = []
36     for i in nfuncs:
37         t = MyThread(funcs[i], (q, nloops))
38         threads.append(t)
39
40     for i in nfuncs:
41         threads[i].start()
42
43     for i in nfuncs:
44         threads[i].join()
45
46     print ‘all DONE‘
47
48 if __name__ == ‘__main__‘:
49     main()

prodcons.py

18.6 相关模块

?  concurrency with python threading, for  parallel programming, please refer to mutliprocesses module

时间: 2024-11-03 03:25:48

18 多线程编程 - 《Python 核心编程》的相关文章

python核心编程--笔记

python核心编程--笔记 的解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找python路径 1.4 –v   冗余输出(导入语句详细追踪) 1.5 –m mod 将一个模块以脚本形式运行 1.6 –Q opt 除法选项(参阅文档) 1.7 –c cmd 运行以命令行字符串心事提交的python脚本 1.8 file   以给定的文件运行python脚本 2 _在解释器中表示最后

Python核心编程 第3版 中文版pdf

[下载地址] <Python核心编程(第3版)>是经典畅销图书<Python核心编程(第二版)>的全新升级版本,总共分为3部分.第1部分为讲解了Python的一些通用应用,包括正则表达式.网络编程.Internet客户端编程.多线程编程.GUI编程.数据库编程.Microsoft Office编程.扩展Python等内容.第2部分讲解了与Web开发相关的主题,包括Web客户端和服务器.CGI和WSGI相关的Web编程.Django Web框架.云计算.高级Web服务.第3部分则为一

Python核心编程(第二版) 第六章习题答案

6–1.字符串.string 模块中是否有一种字符串方法或者函数可以帮我鉴定一下一个字符串是否是另一个大字符串的一部分? 答:有,string.find(str,beg,end) 6–2.字符串标识符.修改例 6-1 的 idcheck.py 脚本,使之可以检测长度为一的标识符,并且可以识别 Python 关键字,对后一个要求,你可以使用 keyword 模块(特别是 keyword.kelist)来帮你. 1 #!/usr/bin/python 2 3 import string 4 impo

Python核心编程这本书的一些错误

<Python核心编程第二版>这本书比<Python基础教程第二版修订版>详细很多,丰富了很多细节,虽然它是一本经典的入门书,但我发现还是存在一些明显的错误.在面向对象编程这一章,有两个错误 1).它说任何类都有一些内置的特殊的类属性(即程序员不在类中定义也会存在),见截图 2).它说__new__方法比__init__方法更像是类的构造器.见截图: 下面进行测试: 1 #encoding:utf-8 2 class MyClass(): 3 def doPrint(self):

学习《Python核心编程》做一下知识点提要,方便复习(一)

学习<Python核心编程>做一下知识点提要,方便复习. 计算机语言的本质是什么? a-z.A-Z.符号.数字等等组合成符合语法的字符串.供编译器.解释器翻译. 字母组合后产生各种变化拿python来说就是.keyword.数值,类,函数,运算符,操作符...... 1.变量不用声明,类型不固定 2.True,False = False,True读出了什么?True是个bool()类实例 3.类型工厂函数就是python2.2后把int() bool()等对数据类型操作的函数分装成对象 类 了

Python核心编程(第二版) 第五章习题答案

5-1.整型.讲讲Python普通整型和长整型的区别. 答:Python 的标准整数类型是最通用的数字类型.在大多数 32 位机器上,标准整数类型的取值范围是-2**31到 2**31-1,也就是-2,147,483,648 到 2,147,483,647.如果在 64 位机器上使用 64 位编译器编译 Python,那么在这个系统上的整数将是 64 位. Python 的长整数类型能表达的数值仅仅与你的机器支持的(虚拟)内存大小有关. 5-2.操作符.(a)写一个函数,计算并返回两个数的乘积.

Python核心编程第五章习题

Python核心编程-第五章-习题 5.1  整形,讲讲Python普通整形与长整形的区别? Python的标准整形类型是最通用的数字类型.在大多数32位机器上,标准整形类型的取值范围是-2**32-2**32 - 1. Python的长整型类型能表达的数值仅仅与你的机器支持的(虚拟)内存大小有关,换句话说,Python能轻松表达很大的整数. 长整型类型是标准整形类型的超集,当程序需要使用比标准整形更大的整型时,可以使用长整型类型,在整型值后面添加L,表示这个为长整型,3.0版本已经统一称为为整

python核心编程--第八章 8.15 练习

#!/usr/bin/python # -*- coding: utf-8 -*- # 8–2. 循环. 编写一个程序, 让用户输入三个数字: (f)rom, (t)o, 和 (i)ncrement . # 以 i为步长, 从 f 计数到 t , 包括 f 和 t . 例如, 如果输入的是 f == 2, # t == 26, i == 4 , 程序将输出 2, 6, 10, 14, 18, 22, 26. f = int(raw_input("Please input from: "

python核心编程第二版

初学Python这是一本有关Python开发的指南涵盖近期发布的Pyttlon版本的核心功能特性,而不仅仅是语法学习更多的高阶内容,如正则表达式.网络.多线程.图形用户界面.Web/CGl和Python扩展等包括几个全新的章节,关于数据库.网络客户端.Java/Jytt30n和Microsoft Office等 展示数以百计的代码片段.交互实例和大量加强您的Python技能的实用练习"对Wesley Chun<Python核心编程>第二版的漫长等待是值得的--它的深邃.它的全面,以及

《Python核心编程》 第八章 条件和循环

8–1.条件语句. 请看下边的代码 # statement A if x > 0: # statement B pass elif x < 0: # statement C pass else: # statement D pass # statement E (a)如果 x< 0 , 上面哪个语句(A, B, C, D, E)将被执行 (b)如果 x== 0 , 上面哪个居于将被执行? (c)如果 x> 0 , 上面哪个语句将被执行? 答: a: A,C,E b: A,D,E c