实现模块

  1. thread:多线程的底层支持模块,一般不建议使用;
  2. threading:对thread进行了封装,将一些线程的操作对象化

python 启动一个线程有两种方式

  1. thread.start_new_thread( print_time, (“Thread-1”, 2, ) )
  2. thread1 = myThread(1, “Thread-1”, 1)

函数方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import thread
import time

# 为线程定义一个函数
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print "%s: %s" % ( threadName, time.ctime(time.time()) )

# 创建两个线程
try:
thread.start_new_thread( print_time, ("Thread-1", 2, ) )
thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print "Error: unable to start thread"

while 1:
pass

类方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import threading
import time

exitFlag = 0

class myThread (threading.Thread): #继承父类threading.Thread
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self): #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
print "Starting " + self.name
print_time(self.name, self.counter, 5)
print "Exiting " + self.name

def print_time(threadName, delay, counter):
while counter:
if exitFlag:
thread.exit()
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启线程
thread1.start()
thread2.start()

print "Exiting Main Thread"

threading.Thread类

  • 构造函数:threading.Thread(group=None, target=None, name=None, args=(), kwargs={})

group为保留参数,暂时无用;target为可调用的对象;name为线程的名字,注意多个线程可以有相同的名字;args是一个参数的tuple;kwargs为命令行参数的字典。

  • name,getName(),setName(): 获取和设置线程的名字
  • ident: 线程的唯一标识。线程启动后就会有,线程退出后被回收
  • start(): 启动线程
  • join(): 等待另一个线程结束后再运行。 join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的join()方法,直到线程A执行完毕后,才会继续执行线程B。
  • is_alive(): 返回线程是否还存活着。
  • daemon, isDaemon,setDaemon: 判断线程是否是守护线程,设置为守护线程(没有用户线程时自动退出的线程,如垃圾回收线程)。

在多线程编程中,t.setDaemon(True) / t.daemon = True

在底层模块中,只要主线程技结束了,其他线程都会结束
如果setDaemon(True),主线程结束,所有子线程都将结束
如果setDaemon(False),主线程将等待该线程结束,等同于你调用线程的join方法

join方法的作用是阻塞主进程,

守护进程

一般来说,所有的线程都完成工作以后,程序才会退出。

如果一个线程被设置为daemon,那么主线程退出的时候,它马上就退出了,这时候为了防止这种情况,可以调用join函数,线程调用join函数后,主线程就会等待子线程退出后才退出,而子线程执行的代码如果不能正常退出时那主线程也一直会等待,如果在join时加上一个超时时间,那主线程只等待设置的超时时间后主线程就退出。

线程间通信 - event

可以通过event,event.set()可以向线程发出信号,event.is_set()判断event是否被set

1
2
3
4
5
6
7
event = threading.Event()

# 发出event被set的信号
event.set()

# 判断event是否被set
event.is_set()

线程间同步 - lock

1
2
3
4
5
6
7
8
# 创建一个锁
lock = threading.Lock()

# 操作的时候先获取一个操作权限,生成一个Lock锁对象,同thread模块中的thread.allocate_lock,锁的用法也相同,使用acquire()获取,release()释放。
lock.acquire()

# 操作完成后,将锁释放
lock.release()

线程池

服务器处理链接最简单的做法是:当一个链接进来的时候,起一个线程来专门处理这个链接。当处理完这个链接以后,关掉这个链接,并结束掉这个线程。
当有很多大量短小的任务的时候,线程创建和销毁的开销很大。
为了提高效率,减少创建和销毁的开销,就预先创建一批线程,这一批线程就是线程池。