【并发编程】多线程

目录

一、什么是线程

二、开启线程的两种方式

三、多线程与多进程的区别

四、守护线程


一、什么是线程

1.1 概念

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。

1.2 进程和线程的区别

1、一个程序至少有一个进程,一个进程至少有一个线程。(进程可以理解成线程的容器)

2、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

3、线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

4、进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

二、开启线程的两种方式

2.1 threading模块介绍

threading模块的接口与multiprocess模块很相像。二者在使用层面,有很大的相似性,因而不再详细介绍。

2.2 开启线程的两种方式

方式一:调用内置的类

 1 import time,random
 2 from threading import Thread
 3 
 4 
 5 def piao(name):
 6     print("%s is piaoing" % name)
 7     time.sleep(random.randrange(1,5))
 8     print("%s piao end" % name)
 9 
10 
11 if __name__ =="__main__":
12     t1 = Thread(target=piao,args=("egon",))
13 
14     t1.start()
15     print("主进程") #每开一个进程,默认有一个线程
16     #所以当前有一个进程一个线程
View Code

方式二:自定义类

 1 import time
 2 from threading import Thread
 3 
 4 
 5 class MyThread(Thread):
 6     def __init__(self,name):
 7         super().__init__()
 8         self.name = name
 9 
10     def run(self):
11         print("%s is piaoing" % self.name)
12         time.sleep(2)
13         print("%s is running" % self.name)
14 
15 
16 if __name__ == "__main__":
17     t1 = MyThread("egon")
18     t1.start()
19     print("主进程")
View Code

三、多线程与多进程的区别

1 创建进程的开销远大于线程,可利用time模块来对比所耗时间。

 1 from threading import Thread
 2 import time
 3 
 4 def work(start):
 5     stop = time.time()
 6     print("开启线程所用时间为%.5f秒" % (stop - start))
 7 
 8 
 9 if __name__ == '__main__':
10     start = time.time()
11     t=Thread(target=work,args=(start,))
12     t.start()
13 
14 
15 #运行结果如下:
16 开启线程所用时间为0.00050秒
创建线程
 1 from multiprocessing import Process
 2 import time
 3 
 4 def work(start):
 5     stop = time.time()
 6     print("开启子进程所用时间为%.5f秒" % (stop - start))
 7 
 8 
 9 if __name__ == '__main__':
10     start = time.time()
11     p=Process(target=work,args=(start,))
12     p.start()
13 
14 
15 #运行结果如下:
16 开启子进程所用时间为0.14338秒
创建进程

2 在主进程下开启多个线程,各线程与主线程pid相同;而开启多个进程,每个进程都用不同的pid。因为同一进程内多个线程共享该进程的内存空间,而各进程间内存空间相互隔离。

 1 from threading import Thread
 2 import os
 3 
 4 def work():
 5     print('hello',os.getpid())
 6 
 7 if __name__ == '__main__':
 8     t1=Thread(target=work)
 9     t2=Thread(target=work)
10     t1.start()
11     t2.start()
12     print('主线程/主进程pid',os.getpid())
13 
14 运行结果如下:
15 hello 21188
16 hello 21188
17 主线程/主进程pid 21188
多线程
 1 from multiprocessing import Process
 2 import os
 3 
 4 def work():
 5     print('hello',os.getpid())
 6 
 7 if __name__ == '__main__':
 8     p1=Process(target=work)
 9     p2=Process(target=work)
10     p1.start()
11     p2.start()
12     print('主线程/主进程',os.getpid())
13 
14 
15 #运行结果如下
16 主线程/主进程 22292
17 hello 1160
18 hello 23292
多进程

四、守护线程

无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁。需要强调的是:运行完毕并非终止运行。

1、对主进程来说,运行完毕指的是主进程代码运行完毕
2、对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕

即:

1、主进程在其代码结束后就已经算运行完毕(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程)才会结束。
2、主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。

验证如下:

 1 from threading import Thread
 2 import time
 3 
 4 def foo():
 5     print(123)
 6     time.sleep(1)
 7     print("end123")
 8 
 9 def bar():
10     print(456)
11     time.sleep(3)
12     print("end456")
13 
14 if __name__ == '__main__':
15     t1=Thread(target=foo)
16     t2=Thread(target=bar)
17 
18     t1.daemon=True
19     t1.start()
20     t2.start()
21     print("main-------")
22 
23 
24 #运行结果如下
25 123
26 456
27 main-------
28 end123
29 end456
View Code

线程t1,t2洗后开启,打印出123,456.紧接着主线程打印出main-------。此时,主线程需要等待非守护线程t2结束,在此期间,t1线程打印end123,然后t2打印end456

猜你喜欢

转载自www.cnblogs.com/chuanxiaopang/p/10162751.html