一、什么是多进程
进程就是正在运行的程序比如你的系统现在运行着的微信就是一个进程,一旦你的微信运行起来系统就会给微信分配了内存和资源
合)
一个进程有一个虚拟的地址空间、可执行的代码、操作系统的接口、安全的上下文(记录启动该进程的用户和权限等等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间),还要有至少一个线程。
每一个进程启动时都会最先产生一个线程,即主线程。然后主线程会再创建其他的子线程。
那什么是单进程呢?
单进程就是说你的电脑只能做一件事情,比如你在电脑打开了微信就不能再去打开淘宝了
但是你会发现现在你的电脑很是牛逼,可以一边看片一边听歌可以一边玩游戏一边撸代码,这就是多进程
你的电脑在同一段时间里面可以 “同时” 执行多个任务
二、什么是多线程
线程(有时候称为轻量级进程)与进程类似,不过它们是在同一个进程下执行的,并共享相同的上下文。可以将它们认为是在一个主进程或“主线程”中并行运行的一些“迷你进程”
多线程类似于同时执行多个不同程序,多线程运行有如下优点:
使用线程可以把占据长时间的程序中的任务放到后台去处理
用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
程序的运行速度可能加快
在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
线程在执行过程中与进程还是有区别的。每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
线程可以被抢占(中断)。
在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) – 这就是线程的退让。
三、线程的实现
Python3 通过两个标准库 threading 提供对线程的支持
- threading 模块的对象列表
- Thread 对象常用属性和方法
四、多线程示例
python通过Thread对象创建一个多线程实例,主要有3种方式
创建 Thread 的实例,传给它一个函数
创建 Thread 的实例,传给它一个可调用的类实例
派生 Thread 的子类,并创建子类的实例
- 创建 Thread 的实例,传给它一个函数
import threading
from time import sleep,ctime
loops = [4,2]
def loop(nloop,nsec):
print("start loop",nloop,"at:",ctime())
sleep(nsec)
print("loop",nloop,"done at:",ctime())
def main():
print("Starting at:",ctime())
threads = []
nloops = range(len(loops))
# 完成所有线程分配,并不立即开始执行
for i in nloops:
t = threading.Thread(target=loop,args=(i,loops[i]))
threads.append(t)
# 开始调用 start 方法,同时开始所有线程
for i in nloops:
threads[i].start()
# join 方法:主线程等待所有子线程执行完成,再执行主线程接下来的操作
for i in nloops:
threads[i].join()
print("All done at:",ctime())
if __name__ == '__main__':
main()
- 创建 Thread 的实例,传给它一个可调用的类实例
import threading
from time import sleep,ctime
loops = [4,2]
class ThreadFunc():
def __init__(self,func,args,name=""):
self.name = name
self.func = func
self.args = args
# 使类具有函数行为,就像函数的代理(proxy)
def __call__(self,):
self.func(*self.args)
def loop(nloop,nsec):
print("start loop",nloop,"at:",ctime())
sleep(nsec)
print("loop",nloop,"done at:",ctime())
def main():
print("Starting at:",ctime())
threads = []
nloops = range(len(loops))
# 完成所有线程分配,并不立即开始执行
for i in nloops:
# loop.__name__ 获得函数的名字
t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
threads.append(t)
# 开始调用 start 方法,同时开始所有线程
for i in nloops:
threads[i].start()
# join 方法:主线程等待所有子线程执行完成,再执行主线程接下来的操作
for i in nloops:
threads[i].join()
print("All done at:",ctime())
if __name__ == '__main__':
main()
- 派生 Thread 的子类,并创建子类的实例
mthread.py
import threading
from time import sleep,ctime
class MyThread(threading.Thread):
def __init__(self,func,args,name=""):
super(MyThread, self).__init__()
self.name = name
self.func = func
self.args = args
def get_res(self):
return self.res
def run(self):
print("Starting",self.name,"at",ctime())
self.res = self.func(*self.args)
print(self.name,"finish at:",ctime())
Mythread 为 threading.Thread 的派生类
from mythread import MyThread
from time import sleep,ctime
# 斐波那契数列
def fib(x):
sleep(0.005)
if x<2:return 1
return (fib(x-2) + fib(x-1))
# 阶乘
def fac(x):
sleep(0.1)
if x<2:return 1
return (x*fac(x-1))
# 累加
def sum(x):
sleep(0.1)
if x<2:return 1
return (x+sum(x-1))
funcs = [fib,fac,sum]
n=12
def main():
nfuns = range(len(funcs))
print("---SINGLE THREAD---")
for i in nfuns:
print("Starting",funcs[i].__name__,"at:",ctime())
print(funcs[i](n))
print(funcs[i].__name__,"finish at:",ctime())
print("\n---MULTIPLE THRADS---")
threads = []
# 完成所有线程分配,但是并不开始执行
for i in nfuns:
t = MyThread(funcs[i],(n,),funcs[i].__name__)
threads.append(t)
# 开始所有的线程
for i in nfuns:
threads[i].start()
for i in nfuns:
threads[i].join()
print(threads[i].get_res())
print("ALL Done")
if __name__=='__main__':
main()
由结果可知,以单线程模式运行时,只是简单地依次调用每个函数,并在函数执行结束后立即显示相应的结果
而以多线程模式运行时,并不会立即显示结果。
因为我们希望让 Mythread 类越通用越好(有输出和没有输出都能够执行),我们要一直等到所有线程都执行结束,然后调用get_res()方法来最终显示每个函数的返回值
- 通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
super().__init__()
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("开始线程:" + self.name)
print_time(self.name, self.counter, 5)
print ("退出线程:" + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("退出主线程")