多线程和多进程是什么自行google补脑
对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂。所以,这里力图用简单的例子,让你对多线程有个初步的认识。
单线程
在好些年前的MS-DOS时代,操作系统处理问题都是单任务的,我想做听音乐和看电影两件事儿,那么一定要先排一下顺序。
(好吧!我们不纠结在DOS时代是否有听音乐和看影的应用。^_^)
from time import ctime,sleepdef music(): for i in range(2): print "I was listening to music. %s" %ctime() sleep(1)def move(): for i in range(2): print "I was at the movies! %s" %ctime() sleep(5)if __name__ == '__main__': music() move() print "all over %s" %ctime()
我们先听了一首音乐,通过for循环来控制音乐的播放了两次,每首音乐播放需要1秒钟,sleep()来控制音乐播放的时长。接着我们又看了一场电影,
每一场电影需要5秒钟,因为太好看了,所以我也通过for循环看两遍。在整个休闲娱乐活动结束后,我通过
print "all over %s" %ctime()
看了一下当前时间,差不多该睡觉了。
运行结果:
>>=========================== RESTART ================================ >>> I was listening to music. Thu Apr 17 10:47:08 2014I was listening to music. Thu Apr 17 10:47:09 2014I was at the movies! Thu Apr 17 10:47:10 2014I was at the movies! Thu Apr 17 10:47:15 2014all over Thu Apr 17 10:47:20 2014
其实,music()和move()更应该被看作是音乐和视频播放器,至于要播放什么歌曲和视频应该由我们使用时决定。所以,我们对上面代码做了改造:
#coding=utf-8import threadingfrom time import ctime,sleepdef 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()
对music()和move()进行了传参处理。体验中国经典歌曲和欧美大片文化。
运行结果:
>>> ======================== RESTART ================================ >>> I was listening to 爱情买卖. Thu Apr 17 11:48:59 2014I was listening to 爱情买卖. Thu Apr 17 11:49:00 2014I was at the 阿凡达! Thu Apr 17 11:49:01 2014I was at the 阿凡达! Thu Apr 17 11:49:06 2014all over Thu Apr 17 11:49:11 2014
多线程
科技在发展,时代在进步,我们的CPU也越来越快,CPU抱怨,P大点事儿占了我一定的时间,其实我同时干多个活都没问题的;于是,操作系统就进入了多任务时代。我们听着音乐吃着火锅的不在是梦想。
python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点,在threading 得到了弥补,为了不浪费你和时间,所以我们直接学习threading 就可以了。
继续对上面的例子进行改造,引入threadring来同时播放音乐和视频:
#coding=utf-8import threadingfrom time import ctime,sleepdef 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()
import threading
首先导入threading 模块,这是使用多线程的前提。
threads = []
t1 = threading.Thread(target=music,args=(u'爱情买卖',))
threads.append(t1)
创建了threads数组,创建线程t1,使用threading.Thread()方法,在这个方法中调用music方法target=music,args方法对music进行传参。 把创建好的线程t1装到threads数组中。
接着以同样的方式创建线程t2,并把t2也装到threads数组。
for t in threads:
t.setDaemon(True)
t.start()
最后通过for循环遍历数组。(数组被装载了t1和t2两个线程)
setDaemon()
setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print "all over %s" %ctime()后,没有等待子线程,直接就退出了,同时子线程也一同结束。
start()
开始线程活动。
运行结果:
>>> ========================= RESTART ================================ >>> 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
从执行结果来看,子线程(muisc 、move )和主线程(print "all over %s" %ctime())都是同一时间启动,但由于主线程执行完结束,所以导致子线程也终止。
继续调整程序:
...if __name__ == '__main__': for t in threads: t.setDaemon(True) t.start() t.join() print "all over %s" %ctime()
我们只对上面的程序加了个join()方法,用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
注意: join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。
运行结果:
>>> ========================= RESTART ================================ >>> I was listening to 爱情买卖. Thu Apr 17 13:04:11 2014 I was at the 阿凡达! Thu Apr 17 13:04:11 2014I was listening to 爱情买卖. Thu Apr 17 13:04:12 2014I was at the 阿凡达! Thu Apr 17 13:04:16 2014all over Thu Apr 17 13:04:21 2014
从执行结果可看到,music 和move 是同时启动的。
开始时间4分11秒,直到调用主进程为4分22秒,总耗时为10秒。从单线程时减少了2秒,我们可以把music的sleep()的时间调整为4秒。
...def music(func): for i in range(2): print "I was listening to %s. %s" %(func,ctime()) sleep(4) ...
执行结果:
>>> ====================== RESTART ================================ >>> I was listening to 爱情买卖. Thu Apr 17 13:11:27 2014I was at the 阿凡达! Thu Apr 17 13:11:27 2014I was listening to 爱情买卖. Thu Apr 17 13:11:31 2014I was at the 阿凡达! Thu Apr 17 13:11:32 2014all over Thu Apr 17 13:11:37 2014
子线程启动11分27秒,主线程运行11分37秒。
虽然music每首歌曲从1秒延长到了4 ,但通多程线的方式运行脚本,总的时间没变化。
本文从感性上让你快速理解python多线程的使用,更详细的使用请参考其它文档或资料。
==========================================================
class threading.Thread()说明:
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
This constructor should always be called with keyword arguments. Arguments are:
group should be None; reserved for future extension when a ThreadGroup class is implemented.
target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.
name is the thread name. By default, a unique name is constructed of the form “Thread-N” where N is a small decimal number.
args is the argument tuple for the target invocation. Defaults to ().
kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}.
If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing
anything else to the thread.
2014-11-18 20:18
@ journeyto这个就是最后一个t的值比如123for i in [1,2]: passprint i试试就知道了 #8楼 刘单纯 2015-01-04 20:37
写的真的很棒,非常的通俗易懂! #9楼 最菜的 2015-01-08 17:29
楼主不去做老师可惜了啊!很详细,知道新手想知道什么,不愧是测试人员 #10楼 MyStitch 2015-01-28 17:44
...if __name__ == '__main__':for t in threads:t.setDaemon(True)t.start()t.join()print "all over %s" %ctime()这个地方写的有问题,如果前面的进程执行速度较慢,后面的进程执行速度快,但是只有最后一个进程设置了t.join(),会导致前面的进程被主线程终止。 #11楼 长生劫 2015-02-09 18:01
楼主最后一个例子调用.join()的时候有点问题,希望楼主修改一下。你把music中sleep(7)休眠时间改为大于5 问题就暴露出来了,当t2线程结束之后,程序结束,但是t1进程还没有执行完毕,这明显与我们的初衷不符。所以建议改成for t in threads:t.join()可避免此问题 #12楼 智慧IT人生 2015-02-27 10:04
最后的主函数可以改成以下代码,就什么为题都没了:12345678if __name__ == '__main__': for t in threads: t.start() for t in threads: t.join() print "all over %s" %ctime() #13楼 以尹天下 2015-03-08 17:56
赞一个, #14楼 up-up 2015-06-12 11:21
有不少有效的评论,谢谢楼主以及下面补充完善的人! #15楼 王小北 2015-09-15 21:35
通俗易懂赞 #16楼 成王之路 2015-09-18 10:55
楼主讲的很详细,必须赞一个!但是对于我们初学者很费劲,要是能图文并茂深入讲解就好了,我给你推荐一个不错的博文。Python基本语法,python入门到精通[二]最近园子新开的python系列,一步步从入门开始学习。 #17楼 yeayee 2015-11-06 09:28
#18楼 脚本小娃子 2016-02-16 00:39
亲测好使,通俗易懂 #19楼 songshijia88888 2016-03-19 18:59
电影是movie,示例代码写成move了 #20楼 leeypp 2016-03-24 16:50
@ songshijia88888这都是小问题,不影响整体性就可以了 #21楼 leeypp 2016-03-24 16:51
楼主写的很不错,点赞 #22楼 kater_ku 2016-05-18 17:10
import threadingfrom time import sleep,ctimedef musci(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=musci('love'),args=(u'love',))threads.append(t1)t2 = threading.Thread(target=move('tokyo hot'),args=(u'tokyo hot',))threads.append(t2)if __name__ == '__main__':for t in threads:t.setDaemon(True)t.start()print('all over %s')%ctime()帮忙看下为什么不行:C:\Python27\python.exe C:/Users/ku/PycharmProjects/untitled1/518i was listening to love .Wed May 18 17:05:37 2016i was listening to love .Wed May 18 17:05:38 2016i was at the tokyo hot!Wed May 18 17:05:39 2016i was at the tokyo hot!Wed May 18 17:05:44 2016all over Wed May 18 17:05:49 2016进程已结束,退出代码0 #23楼 赤壁风情
#24楼 柳如烟雨 2016-08-17 10:37
看楼主说“爱情买卖”是中国经典歌曲, 简直笑喷。楼主的讲述生动有趣,作为新手感激不尽! #25楼 AudienL 2016-08-26 11:06
@ journeyto我也在想这个问题,,, #26楼 AudienL 2016-08-26 11:07
@ MyStitch不知道是不是这样,但是感觉这样解释比较合理 #27楼 AudienL 2016-08-26 11:07
@ MyStitch引用...if __name__ == '__main__':for t in threads:t.setDaemon(True)t.start()t.join()print "all over %s" %ctime()这个地方写的有问题,如果前面的进程执行速度较慢,后面的进程执行速度快,但是只有最后一个进程设置了t.join(),会导致前面的进程被主线程终止。不知道是不是这样,但是感觉这样解释比较合理 #28楼 Tiven 2016-12-15 17:50
python3,为什么Thread args传1个字符串参数会报错?为什么传单个字符不报错? #29楼 LearnerC 2016-12-20 11:05
@ Tiven单个参数用元祖的形式传递,需要在后面加一个逗号 #30楼 Tiven 2017-01-09 14:47
#1楼 ☆Ronny丶 2014-04-17 21:06
#2楼 一路漂泊 2014-04-23 16:17
#3楼 nashviller 2014-05-07 14:40
#4楼[楼主] 虫师 2014-05-07 18:44
#5楼 xijunhu2008 2014-06-10 11:11
#6楼 journeyto 2014-08-28 16:22
#7楼 virusdefender