多线程

单线程

from time import ctime,sleep

def music(music_name):
    for i in range(2):
        print('I am listening to %s. %s' %(music_name,ctime()))
        sleep(1)
def move(movie_name):
    for i in range(2):
        print('I am at the %s! %s' %(movie_name,ctime()))
        sleep(5)

if __name__ == '__main__':
    music('夜曲')
    move('阿凡达')
    print('all over %s' %ctime())

执行结果:

I am listening to 夜曲. Fri Dec  1 23:04:30 2017
I am listening to 夜曲. Fri Dec  1 23:04:31 2017
I am at the 阿凡达! Fri Dec  1 23:04:32 2017
I am at the 阿凡达! Fri Dec  1 23:04:37 2017
all over Fri Dec  1 23:04:42 2017

music和move看作是音乐播放器和视频播放器。我们先听了一首《夜曲》,听了两遍,用sleep()来控制音乐播放的时长,然后看大片《阿凡达》,太好看了,也看了2遍。都用for循环进行控制。最后看了下时间该睡觉了:print(‘all over %s’ %ctime())

多线程

科技在发展,时代在进步,我们的CPU也越来越快,CPU抱怨,P大点事儿占了我一定的时间,其实我同时干多个活都没问题的;于是,操作系统就进入了多任务时代。我们听着音乐吃着火锅的不在是梦想。

python提供了两个模块来实现多线程thread和threading,thread有一些缺点,我们一般直接用threading

对上面的例子进行改造:

import threading
from time import ctime,sleep

def music(music_name):
    for i in range(2):
        print('I am listening to %s. %s' %(music_name,ctime()))
        sleep(1)
def move(movie_name):
    for i in range(2):
        print('I am at the %s! %s' %(movie_name,ctime()))
        sleep(5)

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

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

    print('all aver %s' %ctime())

import threading
首先导入threading模块,这是在python中使用多线程的前提

threads = []
threading.Thread(target=music,args=(‘爱情买卖’,))
threads.append(t1)
创建了threads数组,用来存放线程,创建线程t1,用threading.Thread()方法,target参数来接收方法music,args参数用来接收music的参数。然后把创建好的t1线程装到threads数组里面。
接着以同样的方式创建线程t2,装到threads数组里面。

for t in threads:
        t.setDaemon(True)
        t.start()

最后通过for循环遍历数组(数组被装载了t1和t2两个线程)

join()方法
用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞

setDaemon()
setDaemon()将线程设置为守护线程,必须在start()方法调用之前设置,如果不设置为守护线程,程序将会被无限挂起。子线程启动后,父线程也会继续执行下去,当父线程执行完最后一条语句print('all aver %s' %ctime())后,没有等待子线程,直接就退出了,同时子线程也一同结束。

  • join:如在一个线程B中调用threada.join(),则threada结束后,线程B才会接着threada.join()往后运行。
  • setDaemon效果:例如主线程A启动了子线程B,调用b.setDaemaon(True),则主线程结束时,会把子线程B也杀死,与C/C++中得默认效果是一样的。

执行结果:

I am listening to 爱情买卖. Fri Dec  1 23:28:47 2017
I am at the 阿凡达! Fri Dec  1 23:28:47 2017
all aver Fri Dec  1 23:28:47 2017

可以看到子线程(music和movie)和主线程(print “all over %s” %ctime())是同时进行的。但由于主线程执行完结束,倒置子线程也终止。

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

我们只是加了一个t.join()

刚开始不明白t.join()的位置,不太懂。后来观察pycharm也提示我inspection,因为这个t没有被定义,是凭空出来的(因为在循环外面),但是运行起来也没有报错……然后看了文章下面的评论才明白,恍然大悟。有人举例子

for i in [1,2]:
 pass
print i

然后打印出来结果是2
原来是写在for循环外面的i是循环数组中的最后一个元素。这会我就明白了,那t.join()就是指的是t2.join() 。但是这个就出现一个问题,只是为t2 上了一个join,t1没有,那么如果t2结束,t1还没结束的话,那t1还没执行完就被主线程终止。
所以我想,要不要把t.join()放在for循环里面?

    for t in threads:
        t.setDaemon(True)
        t.start()
        t.join()

执行结果变成了这样:

I am listening to 爱情买卖. Fri Dec  1 23:52:22 2017
I am listening to 爱情买卖. Fri Dec  1 23:52:23 2017
I am at the 阿凡达! Fri Dec  1 23:52:24 2017
I am at the 阿凡达! Fri Dec  1 23:52:29 2017
all aver Fri Dec  1 23:52:34 2017

也就是每个子线程执行完才会去执行另外一个子线程,t1执行完才会执行t2,这样就好像和单线程一样了。。所以这样是不对的。这样的执行顺序是t1.setDaemon ->t1.start() ->t1.join();然后接着:t2.setDaemon ->t2.start() ->t2.join()
正确的应该是t1.start() t2.start() 然后t1.join() t2.join()

所以代码改成如下:

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

大功告成。

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值