Python中的多线程与Java,C++中的思想是比较接近的,作用也一样:
- 使用线程可以把占据长时间的程序中的任务放到后台去处理。
- 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
- 程序的运行速度可能加快
- 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
Python通过两个标准库thread和threading提供对线程的支持。
使用thread模块创建线程
函数式:调用thread模块中的start_new_thread()函数来产生新线程。语法如下:
thread.start_new_thread ( function, args[, kwargs] )
- function - 线程函数。
- args - 传递给线程函数的参数,他必须是个tuple类型。
- kwargs - 可选参数。
#-*-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()))
#创建两个线程
def test():
thread.start_new_thread(print_time, ("Thread-1", 1,))
thread.start_new_thread(print_time, ("Thread-2", 2,))
if __name__=="__main__":
test()
"""
防止Unhandled exception in thread started by Error in sys.excepthook问题。
启动线程之后,须确保主线程等待所有子线程返回结果后再退出,如果主线程比子线程早结束,无论其子线程是否是后台线程,都将会中断,抛出这个异常 。
"""
time.sleep(30)
使用Threading模块创建线程
使用Threading模块创建线程,直接从threading.Thread继承,然后重写init方法和run方法:
#-*- coding:utf-8 -*-
import random
import threading
import time
"""
注意文件名不要与python保留字一样,会出现AttributeError:'module' object has no attribute 'Thread'
threading模块中包含方法和Thread类:
"""
#使用Threading模块创建线程,直接从threading.Thread继承,然后重写__init__方法和run方法
exitFlag = 0
class myThread(threading.Thread):
def __init__(self,threadID,threadName,delay):
#调用父类的构造方法
threading.Thread.__init__(self)
self.threadID = threadID
self.threadName = threadName
self.delay = delay
def run(self):
print "Starting" + self.threadName
print_time(self.threadName,self.delay,5)
print "Exiting" + self.threadName
def print_time(threadName,delay,counter):
while counter:
if exitFlag:
threading.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"
线程的同步问题
多线程同步知识点:
一:
当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,
主线程会创建多个子线程,在python中,默认情况下(其实就是setDaemon(False)),
主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束。
二:
当我们使用setDaemon(True)方法(默认为False),设置子线程为守护线程时,主线程一旦执行结束,则全部线程
全部被终止执行,可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止,例如:
for t in thread_list:
t.setDaemon(True)
t.start()
三:
此时join的作用就凸显出来了,join所完成的工作就是线程同步,即主线程任务结束之后,
进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止。
使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。如下:
#-*- coding: utf-8 -*-
import threading
import time
class myThread(threading.Thread):
def __init__(self,threadID,threadName,delay):
threading.Thread.__init__(self)
self.threadID = threadID
self.threadName = threadName
self.delay = delay
def run(self):
print "Starting" + self.threadName
#获得锁,成功获得锁后返回True
#可选的timeout不填时将一直阻塞
#否则超时后将返回False
threadLock.acquire()
print_time(self.threadName,self.delay,3)
#释放锁
threadLock.release()
def print_time(threadName,delay,counter):
while counter:
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
threadLock = threading.Lock()
threads = []
start_time = time.time()
print('Main Thread', threading.current_thread().name)
#创建线程
thread1 = myThread(1,"Thread-1",1)
thread2 = myThread(2,"Thread-2",2)
#开启新线程
thread1.start()
thread2.start()
#添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
#等待所有线程完成
"""
join关键点:
1.我们的计时是对主线程计时,主线程结束,计时随之结束,打印出主线程的用时。
2.主线程的任务完成之后,主线程随之结束,子线程继续执行自己的任务,直到全部的子线程的任务全部结束,程序结束。
"""
for t in threads:
t.join()
#可以看到,主线程一直等待全部的子线程结束之后,主线程自身才结束,程序退出。
print "Exiting Main Thread"
print('Main Thread Over' , threading.current_thread().name)
print('the all time', time.time()-start_time)
优先级队列Queue
#-*- coding:utf-8 -*-
import Queue
import threading
import time
exitFlag = 0
class myThread(threading.Thread):
def __init__(self,ThreadID,name,q):
threading.Thread.__init__(self)
self.ThreadID = ThreadID
self.name = name
self.q = q
def run(self):
print "Starting: " + self.name
process_data(self.name,self.q)
print "Exiting: " + self.name
#取出队列中的元素
def process_data(threadName,q):
while not exitFlag:
queueLock.acquire()
if workQueue.empty():
queueLock.release()
else:
data = workQueue.get()
queueLock.release()
print "%s processing %s" % (threadName,data)
time.sleep(1)
threadList = ["Thread-1","Thread-2","Thread-3"]
nameList = ["One","Two","Three","Four","Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1
#创建线程
for tName in threadList:
thread = myThread(threadID,tName,workQueue)
thread.start()
threads.append(thread)
threadID += 1
#填充队列
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
#等待清空队列
while not workQueue.empty():
pass
#通知线程退出
exitFlag = 1
#等待所有线程退出
for t in threads:
t.join()
print "Exiting Main Thread"