一.程序、进程、线程的概念

1.程序(program):一组功能集合的静态描述,程序至少有一个进程;

2.进程(process):进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动;进程是系统进行资源分配和调度的一个独立单位,拥有自己独立的地址空间;进程至少有一个线程,它们共享进程的地址空间;

3.线程(thread):线程是处理器调度的基本单位,但进程不是,一个进程中可以有多个线程

举例来说:程序相当于一个web系统,进程相当于每个web系统的请求,线程相当于每个请求的内部逻辑实现。


二.多线程--thread模块

格式:thread.start_new_thread(function,args[,kwargs])

传方法名和形参列表,缺点是依赖于主线程的运行时间,若主线程结束,则thread退出,看下面的例子:

import time
import thread
def print_time(thread_name,delay):
    for i in range(10):
        print thread_name+":"+time.ctime()
        time.sleep(delay)      
thread.start_new_thread(print_time,('thread-1',1))
thread.start_new_thread(print_time,('thread-2',2))
time.sleep(100)

两个线程并发执行,如果把最后一句time.sleep(100)注释掉,再次执行,则程序报错,这是因为主线程运行完毕,子线程退出。建议,除非你能控制主线程的执行时间保证子线程能执行完毕,否则还是不要使用了,下面介绍一个多线程中应用更广的模块。


三.多线程--threading模块

1.创建多线程

threading通过对thread模块进行二次封装,提供了更方便的API来操作线程,其主要优点是不依赖于主线程的运行时间,若主线程结束,thread继续执行。Thread是threading模块中最重要的类之一,可以使用它来创建线程。首先创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入,然后重写run方法,注意区分run方法和start方法: 它们都是从Thread继承而来的,run()方法将在线程开启后执行,可以把相关的逻辑写到run方法中(通常把run方法称为活动[Activity]);start()方法用于启动线程

import time
import thread,threading
class myThread(threading.Thread):
    def __init__(self,thread_id,count,delay):
        threading.Thread.__init__(self)
        self.thread_id=thread_id
        self.count=count
        self.delay=delay
    def run(self):
        print 'Thread-'+str(self.thread_id)+' start'
        self.print_time()
        print 'Thread-'+str(self.thread_id)+' end'
    def print_time(self):
        for i in range(self.count):
            print 'Thread-'+str(self.thread_id)+':'+time.ctime()
            time.sleep(self.delay)
print 'Thread-main start!'
thread1=myThread(1,10,1)
thread2=myThread(2,10,2)
thread1.start()
thread2.start()
print 'Thread-main end!'

主线程与两个子线程并发执行,你可以看到当打印出Thread-main end!之后子线程仍在执行。 


2.threading模块常用方法介绍

threading.currentThread() 返回当前活跃的的线程变量

threading.enumerate() 返回活跃线程的资源池,是一个list

threading.activeCount() 返回正在运行的线程数量


3.threading.Thread方法

run() 用以表示线程活动的方法

start() 启动线程活动

join([time]) 等待至线程中止或者是可选的超时,注意在start之后使用

setDaemon(Ture) 设置守护线程,注意在start之前使用

isAlive() 返回线程是否活动的

getName() 返回线程名

setName() 设置线程名

注意join和setDaemon的区别:join方法是等待一个线程执行之后再执行下一个,setDaemon守护线程,所有非守护线程程结束之后守护线程自动结束。


4.线程同步--线程锁

threading.Lock()和threading.RLock()

threadLock=threading.Lock() #创建锁
threadLock.acquire([timeout]) #锁定
threadLock.release() #释放锁

锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。

这两种锁的主要区别是:Lock同一线程不能连续多次acquire,否则死锁;RLock允许在同一线程中被多次acquire。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的锁。