《python核心编程》(多线程编程)

线程和进程

  • 进程:
    计算机程序:磁盘中可执行的,二进制(或其他类型)的数据。它们只有被读取到内存中,被操作系统调用的时候才开始它们的生命期。
    进程:是程序的一次执行。每个进程都要自己的地址空间、内存、数据栈以及其他记录其运行轨迹的辅助数据。
    操作系统管理在其上运行的所有进程,并为这些进程公平的分配时间。
    各个进程有自己的内存空间,数据栈,所以只能使用进程间通信(IPC),而不能之间共享信息。

  • 线程:
    所有线程运行在同一个进程中,共享相同的运行环境。
    一个进程中的各个线程之间共享同一片数据空间,所以线程之间可以比进程之间更方便地共享数据以及湘湖通信。

python、线程和全局解释器锁

python代码由python虚拟机(也叫解释器主循环)来控制。
对python虚拟机的访问由全局解释器锁(GIL)来控制,证书这个锁能保证同一时刻只有一个线程在运行。
多线程环境中,python虚拟机的执行方式:
1)设置GIL
2)切换到一个线程去运行
3)运行:a.指定数量的字节码指令,或者
b.线程主动让步控制(可用time.sleep(0))
4)把线程设置为睡眠状态
5)解锁GIL
6)再次重复以上所有步骤

  • 退出线程
    退出方法:
    thread.exit()
    sys.exit()
    抛出SystemExit异常

thread模块:不建议使用。因为:
1)当主线程退出的时候,所有其他线程没有被清除就退出了
2)它不支持守护线程。
threading模块可以保证所有的子线程都退出后,线程才结束。支持守护线程

threading守护线程的工作原理:
守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求,它就在那等着。如果你设定一个线程为守护线程,就表示你在说这个线程是不重复的,在进程退出的时候,不用等待这个线程退出。
如果你的主线程要退出的时候,不用等待子线程完成,那就设定这些线程的daemon概念。
thread.setDaemon(True):设定线程的daemon标志,表示这个线程不重要
thread.setDaemon(False):等待子线程完成后再退出
thread.isDaemon()判断其daemon标志的值

python提供的多线程编程的模块:
1.thread 提供了基本的线程和锁的支持
2.threading 提供了更高级别,功能更强的线程管理的功能
3.Queue 允许用户创建一个可以用于多个线程之间共享数据的队列数据结构
注意:1和2允许程序员创建和管理线程。

thread模块

提供了基本的同步数据结构锁对象(lock object, 简单锁,互斥锁,互斥量,二值信号量)
thread模块提供的函数:
start_new_thread(function, args, kwargs=None) 产生一个新的线程
allocate_lock() 分配一个LockType类型的锁对象
exit() 让线程退出
LockType类型锁对象方法:
acquire(wait=None) 尝试获取锁对象
locked() 如果获取了锁对象返回True,否则返回False
release() 释放锁

以下示例仅供参考,并不推荐使用thread模块。

	loops = [4,2]

	def loop(nloop, nsec, lock):
		print 'start loop', nloop, 'at:', time.ctime()
		time.sleep(nsec)
		print 'loop', nloop, 'done at:', time.ctime()
		lock.release()
		
	def main_lock():
		print 'starting at:', time.ctime()
		locks = []
		nloops = range(len(loops))
		for i in nloops:
			lock = thread.allocate_lock()
			lock.acquire()			#获得锁,即加锁
			locks.append(lock)
			for i in nloops:
			thread.start_new_thread(loop,(i,loops[i],locks[i]))

		for i in nloops:
			while locks[i].locked(): pass		#检查锁是否完全退出
			print 'all DONE at:', time.ctime()

threading模块

相关的对象:
Thread 表示一个线程的执行的对象
Lock 锁原语对象
RLock 可重入锁对象
Condition 条件变量对象能让一个线程停下来,等待其他线程满足了某个条件
Event 通用的条件变量。多个线程可用等待某个事件的发生;事件发生后所有线程被激活
Semaphore 为等待锁的线程提供一个类似“等候室”的结构
BoundedSemaphore 与Semaphore类似,只是不允许超过初始值
Timer 与Thread相似,只是它要等待一段时间后才开始运行

  • Thread类
    三种创建线程的方法:
    1. 创建一个Thread的实例,传给它一个函数

      示例:

		#!/bin/python

		import time
		import threading

		loops = [4,2]

		def loop(nloop, nsec):
			print 'start loop', nloop, 'at:', time.ctime()
			time.sleep(nsec)
			print 'loop', nloop, 'done at:', time.ctime()
			

		def main_lock():
			print 'starting at:', time.ctime()
			threads = []
			nloops = range(len(loops))
			for i in nloops:
				t = threading.Thread(target=loop, args=(i,loops[i]))
			threads.append(t)
			for i in nloops:
			threads[i].start()   
		 
			for i in nloops:
			threads[i].join()
			print 'all DONE at:', time.ctime()

		if __name__ == "__main__":
			main_lock()

只有要等待线程结束的时候才要调用join()函数

  1. 创建一个Trhead的实例,传给它一个可调用的类对象(更具有面向对象的概念)

     实例:
    
		import time
		import threading

		loops = [4,2]

		class ThreadFunc(object):
			def __init__(self, func, args, name=''):
				self.name = name
				self.func = func
				self.args = args

			def __call__(self):				#重要,调用函数
				apply(self.func, self.args)
			
		def loop(nloop, nsec):
			print 'start loop', nloop, 'at:', time.ctime()
			time.sleep(nsec)
			print 'loop', nloop, 'done at:', time.ctime()
				

		def main_lock():
			print 'starting at:', time.ctime()
			threads = []
			nloops = range(len(loops))
			for i in nloops:
			t = threading.Thread(
				target = ThreadFunc(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:', time.ctime()

		if __name__ == "__main__":
			main_lock()

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

实例: 
import time
	import threading

	loops = [4,2]

	class MyThread(threading.Thread):
		def __init__(self, func, args, name=''):
		threading.Thread.__init__(self)
		self.name = name
		self.func = func
		self.args = args

		def run(self):
		apply(self.func, self.args)
		

	def loop(nloop, nsec):
		print 'start loop', nloop, 'at:', time.ctime()
		time.sleep(nsec)
		print 'loop', nloop, 'done at:', time.ctime()
			

	def main_lock():
		print 'starting at:', time.ctime()
		threads = []
		nloops = range(len(loops))
		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:', time.ctime()

	if __name__ == "__main__":
		main_lock()

注意:
(1)MyThread子类的构造函数一定要先调用基类的构造函数
(2)之前的特殊函数__call__()在子类中,名字要改为run()

将结果保存到实现的self.res属性中,并创建新函数getResult()来得到结果:

	import time
	import threading

	loops = [4,2]

	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:', time.ctime()
		self.res = apply(self.func, self.args)
			print self.name, 'finished at:', time.ctime()
		

	def loop(nloop, nsec):
		#print 'start loop', nloop, 'at:', time.ctime()
		time.sleep(nsec)
		#print 'loop', nloop, 'done at:', time.ctime()
			

	def main_lock():
		print 'starting at:', time.ctime()
		threads = []
		nloops = range(len(loops))
		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:', time.ctime()

	if __name__ == "__main__":
		main_lock()

实例:同时计算斐波那契、累乘、累加:

	import myThread
	import time

	def fib(x):
		time.sleep(0.005)
		if x < 2: return 1
		return (fib(x-2) + fib(x-1))

	def fac(x):
		time.sleep(0.1)
		if x < 2: return 1
		return (x * fac(x-1))

	def sum(x):
		time.sleep(0.1)
		if x < 2: return 1
		return (x + sum(x-1))

	funcs = [fib, fac, sum]
	n = 12

	def main():
		nfuncs = range(len(funcs))
		'''
		# *** SINGLE THREAD ***
		for i in nfuncs:
		print 'starting', funcs[i].__name__, 'at:', time.ctime()
		print funcs[i](n)
		print funcs[i].__name__, 'finished at:', time.ctime()
		'''
		threads = []
		for i in nfuncs:
			t = myThread.MyThread(funcs[i], (n,), funcs[i].__name__)
			threads.append(t)

		for i in nfuncs:
		threads[i].start()

		for i in nfuncs:
		threads[i].join()
		print threads[i].getResult()
		print "all DONE"

	if __name__ == "__main__":
		main()

  • threading模块中的其他函数
    在这里插入图片描述

6.生产者-消费者问题和Queue模块
在这里插入图片描述
Queue模块可以用来进行线程间通信,让各个线程之间共享数据。
现在创建一个队列,让生产者(线程)把新生产的货物放进去供消费者(线程)使用。

  • 实例:
#!/bin/python

	from random import randint
	from time import sleep
	from Queue import Queue
	from myThread import MyThread

	def writeQ(queue):
		print 'producing object for Q...'
		queue.put('xxx', 1)
		print 'size now', queue.qsize

	def readQ(queue):
		val = queue.get(1)
		print 'consumed object from Q... size now', queue.qsize()

	def writer(queue, loops):
		for i in range(loops):
		writeQ(queue)
		sleep(randint(1,3))

	def reader(queue, loops):
		for i in range(loops):
		readQ(queue)
		sleep(randint(2,5))

	funcs = [writer, reader]
	nfuncs = range(len(funcs))

	def main():
		nloops = randint(5,6)
		q = Queue(32)

		threads = []
		for i in nfuncs:
		t = MyThread(funcs[i], (q, nloops), funcs[i].__name__)
		threads.append(t)

		for i in nfuncs:
		threads[i].start()

		for i in nfuncs:
		threads[i].join()
		print "ALL DONE"

	if __name__ == "__main__":
		main()

7.相关模块

猜你喜欢

转载自blog.csdn.net/zhuix7788/article/details/88406653
今日推荐