一、简单入门
import time
from threading import Thread
def say_hellow(name):
time.sleep(2)
print('%s say hello to friends '%name)
if __name__=='__main__':
t=Thread(target=say_hellow,args=('zhangsan',)) #传入(函数名,参数)
t.start()
print('主线程')
"""
输出:
主线程
zhangsan say hello to friends
"""
二、多线程
Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。
threading 模块提供的其他方法:
threading.currentThread()
: 返回当前的线程变量。threading.enumerate()
: 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。threading.activeCount()
: 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
Thread类提供了以下方法:
run()
: 用以表示线程活动的方法。start()
:启动线程活动。join([time])
: 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。isAlive()
: 返回线程是否活动的。getName()
: 返回线程名。setName()
: 设置线程名。
2.1 单线程(串行)
from time import ctime,sleep
def music():
for i in range(2):
print ("我正在听歌,此时时间为:%s" %ctime())
sleep(1)
def movies():
for i in range(2):
print ("我正在看电影,此时时间为:%s" %ctime())
sleep(5)
if __name__ == '__main__':
music()
movies()
print ("娱乐完成 %s" %ctime())
输出:
我正在听歌,此时时间为:Thu Nov 22 10:42:04 2018
我正在听歌,此时时间为:Thu Nov 22 10:42:05 2018
我正在看电影,此时时间为:Thu Nov 22 10:42:06 2018
我正在看电影,此时时间为:Thu Nov 22 10:42:11 2018
娱乐完成 Thu Nov 22 13:42:16 2018
2.2 多线程—未开启线程等待
import threading
from time import ctime,sleep
def music(name):
for i in range(2):
print("{}正在听歌 。此时时间为:{}".format(name,ctime()))
sleep(1)
def movies(movies_name):
for i in range(2):
print ("我在看电影{}。此时时间为:{}" .format(movies_name,ctime()))
sleep(5)
threads = []
t1 = threading.Thread(target=music,args=('张三',))
threads.append(t1)
t2 = threading.Thread(target=movies,args=('举起手来',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
"""
setDaemon(True) 将线程声明为守护线程,必须在start() 方法调用之前设置。
"""
t.setDaemon(True)
t.start()
print ("娱乐完成 %s" %ctime())
输出:
张三正在听歌 。此时时间为:Thu Nov 22 11:13:29 2018
我在看电影举起手来。此时时间为:Thu Nov 22 11:13:29 2018
娱乐完成 Thu Nov 22 11:13:29 2018
(显然上面函数循环未完成就被中止了:父线程执行完后,没有等待子线程,
直接就退出了,同时子线程也一同结束。)
2.3 多线程—开启线程等待
添加t.join()
开启等待就好了
import threading
from time import ctime,sleep
def music(name):
for i in range(2):
print("{}正在听歌 。此时时间为:{}".format(name,ctime()))
sleep(1)
def movies(movies_name):
for i in range(2):
print ("我在看电影{}。此时时间为:{}" .format(movies_name,ctime()))
sleep(5)
threads = []
t1 = threading.Thread(target=music,args=('张三',))
threads.append(t1)
t2 = threading.Thread(target=movies,args=('举起手来',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
for t in threads:
t.join()
print ("娱乐完成 %s" %ctime())
输出:
张三正在听歌 。此时时间为:Thu Nov 22 11:19:30 2018
我在看电影举起手来。此时时间为:Thu Nov 22 11:19:30 2018
张三正在听歌 。此时时间为:Thu Nov 22 11:19:31 2018
我在看电影举起手来。此时时间为:Thu Nov 22 11:19:35 2018
娱乐完成 Thu Nov 22 11:19:40 2018
2.4 多线程—添加线程列表
from time import sleep, ctime
import threading
def muisc(func):
for i in range(2):
print('开始娱乐:{};此时时间为:{}'.format(func, ctime()))
sleep(2)
def move(func):
for i in range(2):
print('开始娱乐:{};此时时间为:{}'.format(func, ctime()))
sleep(5)
def player(name):
r = name.split('.')[1]
if r == 'mp3':
muisc(name)
elif r == 'mp4':
move(name)
else:
print('error: 格式错误!')
list = ['同桌的你.mp3', '阿凡达.mp4']
threads = []
files = range(len(list))
# 创建线程
for i in files:
t = threading.Thread(target=player, args=(list[i],))
threads.append(t)
if __name__ == '__main__':
# 启动线程
for i in files:
threads[i].start()
for i in files:
threads[i].join()
# 主线程
print('娱乐结束!此时时间为:%s' % ctime())
输出:
开始娱乐:同桌的你.mp3;此时时间为:Thu Nov 22 13:53:42 2018
开始娱乐:阿凡达.mp4;此时时间为:Thu Nov 22 13:53:42 2018
开始娱乐:同桌的你.mp3;此时时间为:Thu Nov 22 13:53:44 2018
开始娱乐:阿凡达.mp4;此时时间为:Thu Nov 22 13:53:47 2018
娱乐结束!此时时间为:Thu Nov 22 13:53:52 2018
三、多线程—获取返回值
案例一:
import threading
import time
class MyThread(threading.Thread):
def __init__(self,func,args=()):
super(MyThread,self).__init__()
self.func = func
self.args = args
def run(self):
self.result = self.func(*self.args)
def get_result(self):
try:
return self.result # 如果子线程不使用join方法,此处可能会报没有self.result的错误
except Exception:
return None
request_params = ['lipei_00006.mp3', 'lipei_00007.mp3', 'lipei_00012.mp3', 'lipei_00014.mp3',
'lipei_00021.mp3', 'lipei_00027.mp3', 'lipei_00028.mp3', 'lipei_00035.mp3',
'lipei_00039.mp3', 'lipei_00044.mp3', 'lipei_00047.mp3', 'lipei_00049.mp3',
'lipei_00057.mp3', 'lipei_00058.mp3', 'lipei_00059.mp3', 'lipei_00061.mp3',
'lipei_00066.mp3', 'lipei_00068.mp3', 'lipei_00070.mp3', 'lipei_00081.mp3',
'lipei_00087.mp3', 'lipei_00104.mp3', 'lipei_00106.mp3', 'lipei_00117.mp3']
def function_01(i):
time.sleep(0.2)
print(i)
return i+'_001'
thread_list = []
return_data = []
for i in request_params:
t = MyThread(function_01, (i,))
thread_list.append(t)
t.start()
for t in thread_list:
t.join() # 一定要join,不然主线程比子线程跑的快,会拿不到结果
return_data.append(t.get_result())
print(t.get_result())
案例二:
from collections import deque
queue = deque(["Eric", "John", "Michael"])
queue.append("Terry") # Terry 入队(从后面添加)
queue.append("Graham") # Graham 入队
queue.popleft() # 队首元素出队
print(queue) # 队列中剩下的元素
#输出: deque(['John', 'Michael', 'Terry', 'Graham']))
from time import ctime
import threading
import collections
adress_name = ['广州', '北京']
cldas_sum = collections.deque()
class MyThread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name = name
self.func = func
self.args = args
self.result = self.func(*self.args)
def get_result(self):
try:
return self.result
except Exception:
return None
def loop(adress_n):
cldas_values = []
for k in range(4):
cldas_values.append(adress_n + str(k)) #组合地名+数字
cldas_sum.append(cldas_values)
print(id(cldas_values))
return cldas_sum
def main():
print('start at', ctime())
threads = []
for i in range(len(adress_name)):
t = MyThread(loop, (adress_name[i],), loop.__name__)
threads.append(t)
for i in range(len(adress_name)): # 将任务分发到每个线程,完成后再开始执行start方法
threads[i].start()
for i in range(len(adress_name)): # join()方法等待线程完成
threads[i].join()
print("threads[0]:",threads[0].get_result())
print("threads[1]:",threads[1].get_result())
print('done at:', ctime())
if __name__ == '__main__':
main()
输出:
start at Mon Dec 3 21:37:18 2018
2443873654152
2443873874376
threads[0]: deque([['广州0', '广州1', '广州2', '广州3'], ['北京0', '北京1', '北京2', '北京3']])
threads[1]: deque([['广州0', '广州1', '广州2', '广州3'], ['北京0', '北京1', '北京2', '北京3']])
done at: Mon Dec 3 21:37:18 2018
需要注意的是:
(1)如果多个线程共用一个公共数据,那么我们需要做的就是将这个公共数据设置成队列格式,要不然多个线程共同访问这个数据可能会出错,需要加锁。设置成队列比加锁再放锁效率高多了
(2)线程之间同一个变量id都不一样,还是不知道是否其他线程会涉足另一个线程