写在最前面:python3使用两种模块引入线程的概念
- _thread
- threading(推荐使用)
由于在python2中使用thread模块,而在python3中该模块已经被废弃,使用_thread来兼容,今天的例子都是基于python3的threading
首先,我们来看一下没有用线程的例子:
import time
import threading
from time import ctime,sleep
def First():
for i in range(3):
print("The First start at %s" % ctime())
sleep(1)
def Second():
for i in range(3):
print("The Second start at %s" % ctime())
sleep(5)
if __name__ == '__main__':
First()
Second()
print("all over %s" %ctime())
The First start at Mon Oct 29 16:41:26 2018
The First start at Mon Oct 29 16:41:27 2018
The First start at Mon Oct 29 16:41:28 2018
The Second start at Mon Oct 29 16:41:29 2018
The Second start at Mon Oct 29 16:41:34 2018
The Second start at Mon Oct 29 16:41:39 2018
Exception ignored in: <module 'threading' from 'F:\\leetcode\\threading.py'>
AttributeError: module 'threading' has no attribute '_shutdown'
all over Mon Oct 29 16:41:44 2018
Process finished with exit code 0
一个小插曲,出现了一个报错,这是因为我把这个py文件命名为threading.py和线程本身的模块名重复了
上面的例子很好理解,程序很听话的按照我们调用函数的顺序执行了First,Second,那么有没有办法同时执行呢?
可以,通过threading线程
为了更好的理解threading,我们在启用线程的时候加入参数
import time
import threading
from time import ctime,sleep
def First(name):
for i in range(3):
print("The %s start at %s" % (name, ctime()))
sleep(1)
def Second(name):
for i in range(3):
print("The %s start at %s" % (name, ctime()))
sleep(5)
threads = []
t1 = threading.Thread(target=First,args=(u'First',))
threads.append(t1)
t2 = threading.Thread(target=Second,args=(u'Second',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
print("all over %s" %ctime())
这时的输出结果是:
The First start at Mon Oct 29 17:03:44 2018
The Second start at Mon Oct 29 17:03:44 2018
all over Mon Oct 29 17:03:44 2018
Process finished with exit code 0
大家有没有发现,我们明明在子线程中写了循环遍历,为什么输出只有一个?
这里我们讲一讲setDaemon
setDaemom默认false,当我们置为True时,子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止。所以当for循环结束,所有的子线程被起来后,主线程也结束,此时子线程强制结束。
那如何使得子线程继续执行呢?
import time
import threading
from time import ctime,sleep
def First(name):
for i in range(3):
print("The %s start at %s" % (name, ctime()))
sleep(1)
def Second(name):
for i in range(3):
print("The %s start at %s" % (name, ctime()))
sleep(5)
threads = []
t1 = threading.Thread(target=First,args=(u'First',))
threads.append(t1)
t2 = threading.Thread(target=Second,args=(u'Second',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
#t.setDaemon(True)
t.start()
print("all over %s" %ctime())
此时的结果如下:
The First start at Mon Oct 29 17:08:57 2018
The Second start at Mon Oct 29 17:08:57 2018
all over Mon Oct 29 17:08:57 2018
The First start at Mon Oct 29 17:08:58 2018
The First start at Mon Oct 29 17:08:59 2018
The Second start at Mon Oct 29 17:09:02 2018
The Second start at Mon Oct 29 17:09:07 2018
Process finished with exit code 0
大家可以看到,主线程结束后,子线程继续执行
那么有没有办法使得主线程等待子线程执行完毕再执行呢?
可以,使用join()
import time
import threading
from time import ctime,sleep
def First(name):
for i in range(3):
print("The %s start at %s" % (name, ctime()))
sleep(1)
def Second(name):
for i in range(3):
print("The %s start at %s" % (name, ctime()))
sleep(5)
threads = []
t1 = threading.Thread(target=First,args=(u'First',))
threads.append(t1)
t2 = threading.Thread(target=Second,args=(u'Second',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
t.join()
print("all over %s" %ctime())
这时我们可以清晰的看到
The First start at Mon Oct 29 17:11:14 2018
The Second start at Mon Oct 29 17:11:14 2018
The First start at Mon Oct 29 17:11:15 2018
The First start at Mon Oct 29 17:11:16 2018
The Second start at Mon Oct 29 17:11:19 2018
The Second start at Mon Oct 29 17:11:24 2018
all over Mon Oct 29 17:11:29 2018
Process finished with exit code 0
当所有子线程都结束之后,主线程才开始执行,此时的子线程不需要守护,因为我们使用join()保证了只有当子线程全部结束,主线程才会执行
那如果我们把join()加入for循环里面呢?
The First start at Mon Oct 29 17:29:36 2018
The First start at Mon Oct 29 17:29:37 2018
The First start at Mon Oct 29 17:29:38 2018
The Second start at Mon Oct 29 17:29:39 2018
The Second start at Mon Oct 29 17:29:44 2018
The Second start at Mon Oct 29 17:29:49 2018
all over Mon Oct 29 17:29:54 2018
Process finished with exit code 0
此时,当第一个子线程还没结束时,主线程无法再次调用for循环起第二个子线程,只能等待第一个子线程结束后,开始第二个子线程。
今天头疼,先讲到这儿,最优化和C++算法作业还没写,难受