江湖小白之一起学Python (七)多线程的运用

朱雀 2020-10-23 15:55 918阅读 0赞

爬虫中常用的多线程,多进程,协程等等,今天我们就来说下这个多线程的基本运用,这时候小白可能会问,啥是多线程啊,有啥用啊?客官勿慌,请听在下给你娓娓道来……

我们就拿一个理发店来说,理发店有4个理发师傅,由于跟我一样上进的人比较多,一堆人早早的就起来排队理发了,但这个时候就只有1个师傅在店里,那我们这一堆人就排队等着这个师傅一个一个的理发,过了一段时间剩下的3个师傅也来了,那就同时一下可以4个一起理发,是不是缩短了大家的等待时间,ALL RIGHT!就是这个道理,嗯,我感觉我是明白了,OK, 没明白的没关系,咱们继续……

下面我就写一个简单的例子来说明,首先我们定义一个方法:

  1. def run(n):
  2. time.sleep(1)
  3. print("我是方法:{}".format(n))

这个方法里time.sleep(1)是延迟1秒执行下面的打印,目的是为了方便观察执行的结果。

我们先来个正常情况下执行循环打印0-9的方法,看看所需要的时间是多少:

  1. #开始时间
  2. begintime=time.time()
  3. for i in range(10):
  4. run(i)
  5. #结束时间
  6. endtime=time.time()
  7. print("执行时间:{}".format(endtime-begintime))

在执行前定义下开始时间,在循环结束定义下结束时间,然后打印看下这个过程花费的时间,来,我们看下结果:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2p5bG9uZ2Vy_size_16_color_FFFFFF_t_70

整个过程花了差不多10秒钟的时间,我们改动一下,加入多线程的方法:

  1. #开始时间
  2. begintime=time.time()
  3. for i in range(10):
  4. t=threading.Thread(target=run, args=(i,))
  5. t.start()
  6. #结束时间
  7. endtime=time.time()
  8. print("执行时间:{}".format(endtime-begintime))

这里说明一下,python的多线程首先要引入threading库,threading.Thread这个是调用线程的方式,里面有许多参数,常用的就是上面这个2个基本参数,target=run是条调用上面定义的run()的方法,这里不需要括号和参数,参数放在后面 args=(i,),这里为什么要这样写呢,因为run只有一个参数,args是以数组或元组的形式传递的,如果不加逗号,python解释器认为你传递是个数字而不是数组或者元组的格式,会报错……接着我打印看下上面执行的时间:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2p5bG9uZ2Vy_size_16_color_FFFFFF_t_70 1

看到没,不要惊讶,这个过程只耗时0.002秒,算算正常执行的时间是它的多少倍,这就是多线程的奥妙之处,这里有个伏笔,继续往下看,细心的小白可能发现输出的内容不是按0-9依次展示的,不错,善于观察,正常的for循环是依次有序的执行,而线程是并行执行的,什么是并行,就是同时执行不一样的任务。

里面常用的设置还有很多,简单说下下面2个参数:

  1. t.setDaemon(True) #这个是设置守护线程,意思就是主线程不等待子线程全部完成就执行后面的代码,反之亦然
  2. t.join() #这个表示主线程会等待子线程执行完毕后继续往下执行

想了解更多参数可以去看看threading库的详细介绍,一般情况下只会用到上面所说的,来我们改动下代码看看join的用法:

  1. #开始时间
  2. begintime=time.time()
  3. #定义一个线程池
  4. thread_pool = []
  5. for i in range(10):
  6. t=threading.Thread(target=run, args=(i,))
  7. t.start()
  8. thread_pool.append(t)
  9. for i in thread_pool:
  10. i.join()
  11. #结束时间
  12. endtime=time.time()
  13. print("执行时间:{}".format(endtime-begintime))

我们定义一个线程池,首先将要执行的线程放入到线程池里,我们循环线程池,加入join(),打印看看:

20200515122119837.png

这时候细心的小白可能就要问了,20200515122229716.png,上面的执行时间为什么0.002秒,这里为什么是1秒,而且执行时间显示的位置也不一样,一个在第一行,一个在最后一行,没错,原因其实就在这里,0.002秒的方法是因为直接执行的子线程,我们开始没有加入join(),运行文件后,主线程是不会等待子线程执行完成后再退出的,所以这个时间只是脚本执行的完成的时间,并不包含子线程运行的时间,加入join()后,打印的执行时间就包含了子线程的运行时间,所以真正的总耗时间为1秒,这就是用了多线程和没用多线程的区别。

20200515122902308.png

好了,关于多线程的用法基本也就讲到这里,有兴趣的童鞋可以用我讲的第一章抓取小说网的例子,加入多线程的运用,实现天下小说任君采的境界……

白嫖兄弟们,源码双手奉上:

  1. #coding:utf-8
  2. import threading,time
  3. def run(n):
  4. time.sleep(1)
  5. print("我是方法:{}".format(n))
  6. #开始时间
  7. begintime=time.time()
  8. thread_pool = []
  9. for i in range(10):
  10. t=threading.Thread(target=run, args=(i,))
  11. t.start()
  12. thread_pool.append(t)
  13. for i in thread_pool:
  14. i.join()
  15. #结束时间
  16. endtime=time.time()
  17. print("执行时间:{}".format(endtime-begintime))

发表评论

表情:
评论列表 (有 0 条评论,918人围观)

还没有评论,来说两句吧...

相关阅读