关于threading模块

2017-11-10  本文已影响0人  Dumplingsrush

从网上找到了两篇言简意赅的文章
https://www.cnblogs.com/fnng/p/3670789.html
http://blog.csdn.net/zhangzheng0413/article/details/41728869/
稍微修改总结一下

首先得先明白多个子线程之间是如何同时运行的(python2)

第一种情况:

import threading
from time import ctime,sleep

def music(func):
    for i in range(2):
        print "I was listening to %s. %s" %(func,ctime())
        sleep(1)

def move(func):
    for i in range(2):
        print "I was at the %s! %s" %(func,ctime())
        sleep(5)



if __name__ == '__main__':
    music(u'爱情买卖')
    move(u'阿凡达')

    print "all over %s" %ctime()

运行结果为下

>>> 
I was listening to 爱情买卖. Thu Apr 17 11:48:59 2014
I was listening to 爱情买卖. Thu Apr 17 11:49:00 2014
I was at the 阿凡达! Thu Apr 17 11:49:01 2014
I was at the 阿凡达! Thu Apr 17 11:49:06 2014
all over Thu Apr 17 11:49:11 2014

这种情况比较简单,我们还没有启动子线程,所以输出语句通过time.sleep方法按顺序执行下来


第二种情况我们启用多线程:

import threading
from time import ctime,sleep


def music(func):
    for i in range(2):
        print "I was listening to %s. %s" %(func,ctime())
        sleep(1)

def move(func):
    for i in range(2):
        print "I was at the %s! %s" %(func,ctime())
        sleep(5)

threads = []
t1 = threading.Thread(target=music,args=(u'爱情买卖',))
threads.append(t1)
t2 = threading.Thread(target=move,args=(u'阿凡达',))
threads.append(t2)

if __name__ == '__main__':
    for t in threads:
        t.setDaemon(True)
        t.start()

    print "all over %s" %ctime()

利用threading.Thread(target=xxxx)创建线程,这里我们创建了两个线程,并将他们添加到threads这个list中,这种情况执行的关键在于for循环语句内,setDaemon()为守护线程方法,在文章头的其中一篇内有提到,我们以当前这个情况为例子。
先是for循环,通过setDaemon()我们在主线程中调用了t1.setDaemon(),注意for循环中t1.setDaemon()和t2.setDaemon()设置的主线程都为当前py文件,当设置为True时,如果我们的主线程(也就是当前的py文件)结束了,那么不管t1,t2两个子线程是否完成,都一并和主线程一起退出。所以输出结果如下

>>> 
I was listening to 爱情买卖. Thu Apr 17 12:51:45 2014 I was at the 阿凡达! Thu Apr 17 12:51:45 2014  all over Thu Apr 17 12:51:45 2014

所以当主线程执行完毕后,子线程也终止,也就不再输出,如果我们改True为False时,则输出结果如下

I was listening to 爱情买卖. Fri Nov 10 20:54:20 2017
I was at the 阿凡达! Fri Nov 10 20:54:20 2017
all over Fri Nov 10 20:54:20 2017
I was listening to 爱情买卖. Fri Nov 10 20:54:21 2017
I was at the 阿凡达! Fri Nov 10 20:54:25 2017
[Finished in 10.1s]

因为改为了False,所以即使主线程结束了,子线程 也会接着运行,这里特别注意一点,“all over ...” 输出的位置为结果中间,也就是说主线程并没有阻塞!这也是下面介绍的join()方法与setDaemon(False)最大的不同,join()方法会阻塞主线程。


第三种情况(加入join()方法):

import threading
from time import ctime,sleep


def music(func):
    for i in range(2):
        print "I was listening to %s. %s" %(func,ctime())
        sleep(1)

def move(func):
    for i in range(2):
        print "I was at the %s! %s" %(func,ctime())
        sleep(5)

threads = []
t1 = threading.Thread(target=music,args=(u'爱情买卖',))
threads.append(t1)
t2 = threading.Thread(target=move,args=(u'阿凡达',))
threads.append(t2)

if __name__ == '__main__':
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    print "all over %s" %ctime()

当主线程迅速的执行完第一个for循环时,启动了两个线程,于是主线程接着运行,到了第二个for循环,当执行t1.join()时,主线程被阻塞了,所以必须等待t1线程执行完毕才能接着下一步,接着再执行t2.join()同理。因此执行结果会如下

>>> 
I was listening to 爱情买卖. Thu Apr 17 13:04:11 2014  I was at the 阿凡达! Thu Apr 17 13:04:11 2014

I was listening to 爱情买卖. Thu Apr 17 13:04:12 2014
I was at the 阿凡达! Thu Apr 17 13:04:16 2014
all over Thu Apr 17 13:04:21 2014

如果我们向之前一样往执行语句里面加入setDaemon(True)

if __name__ == '__main__':
    for t in threads:
        t.setDaemon(True)
        t.start()
    for t in threads:
        t.join()
    print "all over %s" %ctime()

因为t.join()阻塞了主线程,所以主线程不可能跑的比子线程快,所以这里的setDaemon(True)也就可有可无了,执行结果也会想同

I was listening to 爱情买卖. Thu Apr 17 13:11:27 2014I was at the 阿凡达! Thu Apr 17 13:11:27 2014

I was listening to 爱情买卖. Thu Apr 17 13:11:31 2014
I was at the 阿凡达! Thu Apr 17 13:11:32 2014
all over Thu Apr 17 13:11:37 2014

关键在于注意理解t.join()和setDaemon(False)的区别,以及通过输出语句的时间对比,体会子进程的执行顺序。如果理解困难可以先由单个子线程开始,后面再尝试添加for循环和多个子线程,同时理解。

上一篇下一篇

猜你喜欢

热点阅读