1、线程理论
- 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
- 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于cpu),而一条流水线必须属于一个车间,一个车间的工作过程是一个进程,车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一条流水线。所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
- 多线程(即多个控制线程)的概念是,在一个进程中存在多个线程,多个线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。例如,北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
2、线程实践
- 开启线程的两种方式
①:方式一
from threading import Thread
import time
def sayhi(name):
time.sleep(2)
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('egon',))
t.start()
print('主线程')
②:方式二
#方式二
from threading import Thread
import time
class Sayhi(Thread):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
time.sleep(2)
print('%s say hello' % self.name)
if __name__ == '__main__':
t = Sayhi('egon')
t.start()
print('主线程')
线程与进程的区别
- 谁的开启速度快?
1、在主进程下开启线程
from threading import Thread
def work():
print('hello')
if __name__ == '__main__':
t=Thread(target=work)
t.start()
print('主线程/主进程')
执行结果如下,几乎是t.start ()的同时就将线程开启了,然后先打印出了hello,证明线程的创建开销极小
hello
主线程/主进程
2、在主进程下开启子进程
from multiprocessing import Process
def work():
print('hello')
if __name__ == '__main__':
#在主进程下开启子进程
p=Process(target=work)
p.start()
print('主线程/主进程')
执行结果如下,p.start ()将开启进程的信号发给操作系统后,操作系统要申请内存空间,让好拷贝父进程地址空间到子进程,开销远大于线程
主线程/主进程
hello
- 瞅一瞅pid?
1、在主进程下开启多个线程,每个线程都跟主进程的pid一样
from threading import Thread
import os
def work():
print('hello',os.getpid())
if __name__ == '__main__':
t1=Thread(target=work)
t2=Thread(target=work)
t1.start()
t2.start()
print('主线程/主进程pid',os.getpid())
执行结果
hello 7939
hello 7939
主线程/主进程 7939
2、开多个进程,每个进程都有不同的pid
from multiprocessing import Process
import os
def work():
print('hello',os.getpid())
if __name__ == '__main__':
p1=Process(target=work)
p2=Process(target=work)
p1.start()
p2.start()
print('主线程/主进程',os.getpid())
执行结果
主线程/主进程 7951
hello 7952
hello 7953
- 同一进程内的线程共享该进程的数据?
1、进程之间地址空间是隔离的
from multiprocessing import Process
import os
def work():
global n
n=0
if __name__ == '__main__':
n=100
p=Process(target=work)
p.start()
p.join()
print('主',n)
执行结果如下,毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100
主 100
2、同一进程内开启的多个线程是共享该进程地址空间的
from threading import Thread
import os
def work():
global n
n=0
if __name__ == '__main__':
n=100
t=Thread(target=work)
t.start()
t.join()
print('主',n)
执行结果如下, 查看结果为0,因为同一进程内的线程之间共享进程内的数据
主 0
Thread的其他属性和方法
Thread实例对象的方法
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。
》threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
验证:
from threading import Thread
import threading
from multiprocessing import Process
import os
def work():
import time
time.sleep(3)
print(threading.current_thread().getName())
if __name__ == '__main__':
#在主进程下开启线程
t=Thread(target=work)
t.start()
print(threading.current_thread().getName())
print(threading.current_thread()) #主线程
print(threading.enumerate()) #连同主线程在内有两个运行的线程
print(threading.active_count())
print('主线程/主进程')
守护线程
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
1、对主进程来说,运行完毕指的是主进程代码运行完毕
2、对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕