线程
线程指的就是代码的执行过程
进程其实是一个资源单位,而进程内的线程才是CPU上的执行单位
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
流水线的工作需要电源,电源就相当于CPU,所以进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是:在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
例如:
北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
线程和进程的区别
1.同一进程下的多个线程共享该进程内的资源
2.创建线程的开销远远小于进程
创建线程的开销远远小于进程
假设我们的软件是一个工厂,该工厂有多条流水线,流水线工作需要电源,电源只有一个即CPU(单核CPU)
一个车间就是一个进程,一个车间至少一条流水线(一个进程至少一个线程)
创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线)
而建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小
进程之间是竞争关系:
车间直接是竞争/抢电源的关系,竞争:不同的进程直接是竞争关系,是不同的程序员写的程序运行的,迅雷抢占其他进程的网速,360把其他进程当做病毒干死
线程之间是协作关系:
一个车间的不同流水线式协同工作的关系:同一个进程的线程之间是合作关系,不会自己干自己
多线程举例
开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,
这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,
键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
开启线程的两种方式
Thread实例对象的方法
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。
threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
1 #方式一
2 from threading import Thread
3 import time
4 def sayhi(name):
5 time.sleep(2)
6 print('%s say hello' %name)
7
8 if __name__ == '__main__':
9 t=Thread(target=sayhi,args=('egon',))
10 t.start()
11 print('主线程')
1 #方式二
2 from threading import Thread
3 import time
4 class Sayhi(Thread):
5 def __init__(self,name):
6 super().__init__()
7 self.name=name
8 def run(self):
9 time.sleep(2)
10 print('%s say hello' % self.name)
11
12
13 if __name__ == '__main__':
14 t = Sayhi('egon')
15 t.start()
16 print('主线程')
统一进程下线程间资源共享
统一进程下的多个线程共享该进程内的资源
代码举例:
1 from threading import Thread
2
3 n = 100
4
5
6 def task():
7 global n
8 n = 0
9
10
11 if __name__ == '__main__':
12 t = Thread(target=task)
13 t.start()
14 t.join()
15 print(n)
守护线程
无论是进程还是线程,都遵循:守护xxx会等待xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
#1.对主进程来说,运行完毕指的是主进程代码运行完毕
#2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
详细解释:
#1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
1 from threading import Thread
2 import time
3 def sayhi(name):
4 time.sleep(2)
5 print('%s say hello' %name)
6
7 if __name__ == '__main__':
8 t=Thread(target=sayhi,args=('egon',))
9 t.setDaemon(True) #必须在t.start()之前设置
10 t.start()
11
12 print('主线程')
13 print(t.is_alive())
14 '''
15 主线程
16 True
17 '''
1 from threading import Thread
2 import time
3 def foo():
4 print(123)
5 time.sleep(1)
6 print("end123")
7
8 def bar():
9 print(456)
10 time.sleep(3)
11 print("end456")
12
13
14 t1=Thread(target=foo)
15 t2=Thread(target=bar)
16
17 t1.daemon=True
18 t1.start()
19 t2.start()
20 print("main-------")
互斥锁
1 from threading import Thread,Lock
2 import time
3
4 mutex=Lock() # 线程是共享资源的,所以不需要把锁当参数传
5 n=100
6 def task():
7 global n
8 mutex.acquire()
9 temp=n
10 time.sleep(0.1)
11 n=temp-1
12 mutex.release()
13
14 if __name__ == '__main__':
15 t_l=[]
16 for i in range(100):
17 t=Thread(target=task)
18 t_l.append(t)
19 t.start()
20
21 for t in t_l:
22 t.join()
23 print(n)