一、线程&进程
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。进程是很多资源的集合。
有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。线程是最小的执行单元,而进程由至少一个线程组成。
我们在做事情的时候,一个人做是比较慢的,如果多个人一起来做的话,就比较快了,程序也是一样的,我们想运行的速度快一点的话,就得使用多进程,或者多线程,在python里面,多线程被很多人诟病,为什么呢,因为Python的解释器使用了GIL的一个叫全局解释器锁,它不能利用多核CPU,只能运行在一个cpu上面,但是你在运行程序的时候,看起来好像还是在一起运行的,是因为操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。这个叫做上下文切换。
二、多线程,python中的多线程使用theading模块
下面是一个简单多线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import threading import time def sayhi(num): #定义每个线程要运行的函数 print ( "running on number:%s" % num) time.sleep( 3 ) if __name__ = = '__main__' : t1 = threading.Thread(target = sayhi,args = ( 1 ,)) #生成一个线程实例 t2 = threading.Thread(target = sayhi,args = ( 2 ,)) #生成另一个线程实例 t1.start() #启动线程 t2.start() #启动另一个线程 |
下面是另一种启动多线程的方式,继承式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import threading import time class MyThread(threading.Thread): def __init__( self ,num): threading.Thread.__init__( self ) self .num = num def run( self ): #定义每个线程要运行的函数 print ( "running on number:%s" % self .num) time.sleep( 3 ) if __name__ = = '__main__' : t1 = MyThread( 1 ) t2 = MyThread( 2 ) t1.start() t2.start() |
这两种方式没有什么区别,两种写法而已,我个人喜欢用第一种,更简单一些。
线程等待,多线程在运行的时候,每个线程都是独立运行的,不受其他的线程干扰,如果想在哪个线程运行完之后,再做其他操作的话,就得等待它完成,那怎么等待呢,使用join,等待线程结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import threading import time def run(): print ( 'qqq' ) time.sleep( 1 ) print ( 'done!' ) lis = [] for i in range ( 5 ): t = threading.Thread(target = run) lis.append(t) t.start() for t in lis: t.join() print ( 'over' ) |
守护线程,什么是守护线程呢,就相当于你是一个国王(非守护线程),然后你有很多仆人(守护线程),这些仆人都是为你服务的,一但你死了,那么你的仆人都给你陪葬。
1
2
3
4
5
6
7
8
9
10
11
|
import threading import time def run(): print ( 'qqq' ) time.sleep( 1 ) print ( 'done!' ) for i in range ( 5 ): t = threading.Thread(target = run) t.setDaemon( True ) t.start() print ( 'over' ) |
线程锁,线程锁就是,很多线程一起在操作一个数据的时候,可能会有问题,就要把这个数据加个锁,同一时间只能有一个线程操作这个数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import threading from threading import Lock num = 0 lock = Lock() #申请一把锁 def run(): global num lock.acquire() #加锁 num + = 1 lock.release() #解锁 lis = [] for i in range ( 5 ): t = threading.Thread(target = run) t.start() lis.append(t) for t in lis: t.join() print ( 'over' ,num) |
下面来个简单的爬虫,看下多线程的效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import threading import requests,time urls = { "baidu" : 'http://www.baidu.com' , "blog" : 'http://www.nnzhp.cn' , "besttest" : 'http://www.besttest.cn' , "taobao" : "http://www.taobao.com" , "jd" : "http://www.jd.com" , } def run(name,url): res = requests.get(url) with open (name + '.html' , 'w' ,encoding = res.encoding) as fw: fw.write(res.text) start_time = time.time() lis = [] for url in urls: t = threading.Thread(target = run,args = (url,urls[url])) t.start() lis.append(t) for t in lis: t.join() end_time = time.time() print ( 'run time is %s' % (end_time - start_time)) #下面是单线程的执行时间 # start_time = time.time() # for url in urls: # run(url,urls[url]) # end_time = time.time() # print('run time is %s'%(end_time-start_time)) |
三、多进程,上面说了Python里面的多线程,是不能利用多核CPU的,如果想利用多核CPU的话,就得使用多进程,python中多进程使用multiprocessing模块。
1
2
3
4
5
6
7
8
|
from multiprocessing import Process import time def f(name): time.sleep( 2 ) print ( 'hello' , name) p = Process(target = f, args = ( 'niu' ,)) p.start() p.join() |
来源:https://www.cnblogs.com/hongdoudou/p/12213661.html