一、线程和进程
1.进程
计算机的程序只是在磁盘上可执行的二进制(或其他类型)文件。只有把它们加载到内存中并被操作系统调用,才拥有其生命周期。进程则是一个执行中的程序。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。操作系统管理其上所有进程的执行,并为这些进程合理的分配时间。进程也可以派生(fork或spwan)新的进程来执行其他任务,不过因为每个新进程也都拥有自己的内存和数据栈等,所以只能采用进程间通信(IPC)的方式共享信息。
2.线程
线程与进程类似,不过它们是在同一个进程下执行的,并共享上下文。可以将它们认为是在一个主进程或“主线程”中并行运行的一些“迷你进程”。
线程包括开始、执行顺序和结束三个部分。它有一个指令指针,用于记录当前运行的上下文。当其他线程运行时,它可以被抢占(中断)和临时挂起(也成睡眠)—-这种做法叫让步。
一个进程中的各个线程与主线程共享同一个数据空间,因为相比于独立的进程而言,线程间的信息共享和通信更加容易。线程一般是以并发方式执行的,正是由于这种并发和数据共享机制,使得多任务间的协调成为可能。当然在单核CPU系统中,因为真正的并发是不可能的,所以线程的执行实际上这样规划的:整个进程的执行过程中,每个线程执行它自己特定的任务,在必要时和其他线程进行结果通信。
当然,这种共享并不是没有风险。如果两个或多个线程访问同一片数据,由于数据访问顺序不同,可能导致结果不一致。这种情况通常称为竞态条件。幸运的是,大多数线程库都有一些同步原语,以允许线程管理器控制执行和访问。
二、Python的threading模块
python提供了多个模块来支持多线程编程,包括:thread、threading、Queue模块等。程序是可以使用thread和threading模块来创建与管理线程。thread模块提供了基本的线程和锁定支持;而threading模块提供了更高级别、功能更全面的线程管理。
1.thread模块
#派生一个新线程,使用给定的args和可选的kwargs来执行function
start_new_thread(function,args,kwargs=None)
#分配 LockType锁对象
allocate_lock()
#给线程退出指令
exit()
LockType锁对象的方法:
#尝试获取锁对象
acquire(wait=None)
#如果获取了锁对象则返回True,反之False
locked()
#释放锁
release()
示例1
#!/usr/bin/python
import thread
from time import sleep,ctime
def loop0():
print 'start loop 0 at:',ctime()
sleep(4)
print 'loop 0 done at:',ctime()
def loop1():
print 'start loop 1 at:',ctime()
sleep(2)
print 'loop 1 done at:',ctime()
def main():
print 'starting at:',ctime()
thread.start_new_thread(loop0,())
thread.start_new_thread(loop1,())
sleep(6)
print 'all DONE at:',ctime()
if __name__=='__main__':
main()
结果:
starting at: Tue Dec 19 15:34:08 2017
start loop 1 at: Tue Dec 19 15:34:08 2017
start loop 0 at: Tue Dec 19 15:34:08 2017
loop 1 done at: Tue Dec 19 15:34:10 2017
loop 0 done at: Tue Dec 19 15:34:12 2017
all DONE at: Tue Dec 19 15:34:14 2017
示例2(线程和锁)
#!/usr/bin/python
import thread
from time import sleep,ctime
loops = [4,2]
def loop(nloop,nsec,lock):
print 'start loop',nloop,'at:',ctime()
sleep(nsec)
print 'loop %s done at:%s' % (nloop,ctime())
lock.release()
def main():
print 'starting at:',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:',ctime()
if __name__=='__main__':
main()
2.threading模块
对 象
Thread #表示一个执行线程对象
Lock #锁原语对象
RLock #可重入锁对象,使单一线程可以(再次)获得已持有的锁(递归锁)
Condition #条件变量对象,使得一个线程等待另一个线程满足特定的"条件",比如改变状态或某个数据值
Event #条件变量的通用版本,任意数量的线程在等待某个事件的发生,在该事件发生后所有线程将被激活。
Semaphore #为线程间共享的有限资源提供了一个"计数器",如果没有可用资源时会被阻塞。
BoundedSemaphore #与Semaphore相似,不过它不允许超过初始值
Timer #与Thread类似,不过它要在运行前等待一段时间
Barrier #创建一个"障碍",必须到达指定数量的线程后才可以继续。
与thread比较,thread不支持守护线程,当主线程退出时,所有子线程,都将终止,而threading支持守护进程,其工作方式为:守护线程一般是一个等待客户端请求服务的服务器。如果没有客户端请求,守护线程就是空闲,如果把一个线程设置为守护线程,就表示这个线程是不重要的,进程退出时不需要等待这个线程执行完毕。
2.1 thread类
Thread 对象的属性和方法
属性
name #线程名
ident #线程的标识符
daemon #布尔标志,表示这个进程是否是守护进程
方法
__init__(group=None,target=None #实例化一个线程对象,需要有一个可调用的target,以及其参数args
,name=None,args=(),kwargs={} #或kwargs。可选参数name或group参数,不过后者还未实现。此外,
,verbose=None,daemon=None) #verbose,标志也是可接受的。
start() #开始执行该进程
run() #定义线程功能的方法
join(timeout=None) #直至启动的线程终止之前一直挂起,除非给出了timeout,否则一直阻塞。
getName() #返回线程名
setName(name) #设置线程名
isAlivel/is_alive() #布尔标志,表示这个线程是否存活。
isDaemon() #如果是守护线程,返回True,反之False
setDaemon(daemonic) #把线程的守护标志设置成布尔值daemonic(必须在线程start()之前调用)
示例(1)threading
#!/usr/bin/python
import threading
from time import sleep,ctime
loops = [4,2]
def loop(nloop,nsec):
print 'start loop',nloop,'at:',ctime()
sleep(nsec)
print 'loop %s done at:%s' % (nloop,ctime())
def main():
print 'starting at:',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() #start threads
for i in nloops:
threads[i].join() #wait for all
print 'all DONE at:',ctime() #threads to finish
if __name__=='__main__':
main()
结果:
starting at: Tue Dec 19 16:46:33 2017
start loop 0 at: Tue Dec 19 16:46:33 2017
start loop 1 at: Tue Dec 19 16:46:33 2017
loop 1 done at:Tue Dec 19 16:46:35 2017
loop 0 done at:Tue Dec 19 16:46:37 2017
all DONE at: Tue Dec 19 16:46:37 2017
示例(2)创建Thread的实例
#!/usr/bin/python
import threading
from time import sleep,ctime
loops = [4,2]
class ThreadFunc(object):
def __init__(self,func,args,name=''):
self.name = name
self.func = func
self.args = args
def __call__(self):
self.func(*self.args)
def loop(nloop,nsec):
print 'start loop',nloop,'at:',ctime()
sleep(nsec)
print 'loop %s done at:%s' % (nloop,ctime())
def main():
print 'starting at:',ctime()
threads = []
nloops = range(len(loops))
for i in nloops: #create all threads
t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
threads.append(t)
for i in nloops:
threads[i].start() #start threads
for i in nloops:
threads[i].join() #wait for all
print 'all DONE at:',ctime() #threads to finish
if __name__=='__main__':
main()
结果:
starting at: Tue Dec 19 17:08:51 2017
start loop 0 at: Tue Dec 19 17:08:51 2017
start loop 1 at: Tue Dec 19 17:08:51 2017
loop 1 done at:Tue Dec 19 17:08:53 2017
loop 0 done at:Tue Dec 19 17:08:55 2017
all DONE at: Tue Dec 19 17:08:55 2017