线程和进程
-
进程:
计算机程序:磁盘中可执行的,二进制(或其他类型)的数据。它们只有被读取到内存中,被操作系统调用的时候才开始它们的生命期。
进程:是程序的一次执行。每个进程都要自己的地址空间、内存、数据栈以及其他记录其运行轨迹的辅助数据。
操作系统管理在其上运行的所有进程,并为这些进程公平的分配时间。
各个进程有自己的内存空间,数据栈,所以只能使用进程间通信(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类
三种创建线程的方法:-
创建一个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()函数
-
创建一个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.相关模块