在之前编写的程序中,我们写过的大多数程序都是在一个地方(一台机器)一次运行一行(解释型顺序执行)。但是,我们可以在多个地方(分布式计算或者网络)同时做很多事(并发)。这样做有很多好处。下面记录几个常见词汇的含义:
进程我们可以理解为是一个可以独立运行的程序单位,比如打开一个浏览器,这就开启了一个浏览器进程;打开一个文本编辑器,这就开启了一个文本编辑器进程。但一个进程中是可以同时处理很多事情的,比如在浏览器中,我们可以在多个选项卡中打开多个页面,有的页面在播放音乐,有的页面在播放视频,有的网页在播放动画,它们可以同时运行,互不干扰。为什么能同时做到同时运行这么多的任务呢?这里就需要引出线程的概念了,其实这一个个任务,实际上就对应着一个个线程的执行。
而进程呢?它就是线程的集合,进程就是由一个或多个线程构成的,线程是操作系统进行运算调度的最小单位,是进程中的一个最小运行单元。比如上面所说的浏览器进程,其中的播放音乐就是一个线程,播放视频也是一个线程,当然其中还有很多其他的线程在同时运行,这些线程的并发或并行执行最后使得整个浏览器可以同时运行这么多的任务。
它是指同一时刻只能有一条指令执行,但是多个线程的对应的指令被快速轮换地执行。比如一个处理器,它先执行线程 A 的指令一段时间,再执行线程 B 的指令一段时间,再切回到线程 A 执行一段时间。
由于处理器执行指令的速度和切换的速度非常非常快,人完全感知不到计算机在这个过程中有多个线程切换上下文执行的操作,这就使得宏观上看起来多个线程在同时运行。但微观上只是这个处理器在连续不断地在多个线程之间切换和执行,每个线程的执行一定会占用这个处理器一个时间片段,同一时刻,其实只有一个线程在执行。
它是指同一时刻,有多条指令在多个处理器上同时执行,并行必须要依赖于多个处理器。不论是从宏观上还是微观上,多个线程都是在同一时刻一起执行的。
并行只能在多处理器系统中存在,如果我们的计算机处理器只有一个核,那就不可能实现并行。而并发在单处理器和多处理器系统中都是可以存在的,因为仅靠一个核,就可以实现并发。
举个例子,比如系统处理器需要同时运行多个线程。如果系统处理器只有一个核,那它只能通过并发的方式来运行这些线程。如果系统处理器有多个核,当一个核在执行一个线程时,另一个核可以执行另一个线程,这样这两个线程就实现了并行执行,当然其他的线程也可能和另外的线程处在同一个核上执行,它们之间就是并发执行。具体的执行方式,就取决于操作系统的调度了。
写个demo测试一下:
#coding=utf-8
import time
def say_sorry():
print("亲爱的,我错了,我能吃饭了吗?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
say_sorry()
#coding=utf-8
import threading
import time
def say_sorry():
print("亲爱的,我错了,我能吃饭了吗?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=say_sorry)
t.start() #启动线程,即让线程开始执行
调用threading.enumerate()
方法,可以查看当前正在运行的线程,该方法返回一个列表
这里我们再来写一个唱、跳rap的代码:
import threading
from time import sleep, ctime
def sing():
for i in range(3):
print("正在唱歌...%d" % i)
sleep(1)
def dance():
for i in range(3):
print("正在跳舞...%d" % i)
sleep(1)
if __name__ == '__main__':
print('---开始---:\n%s' % ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
while True:
length = len(threading.enumerate())
print(threading.enumerate())
print('当前运行的线程数为:%d' % length)
if length <= 1:
break
sleep(0.5)
结果:
---开始---:
Fri May 29 08:37:59 2020
正在唱歌...0
正在跳舞...0
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-1, started 3992)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:3
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-1, started 3992)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:3
正在唱歌...1
正在跳舞...1
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-1, started 3992)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:3
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-1, started 3992)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:3
正在唱歌...2
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-1, started 3992)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:3
正在跳舞...2
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-1, started 3992)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:3
[<_MainThread(MainThread, started 11744)>, <Thread(Thread-2, started 7696)>]
当前运行的线程数为:2
[<_MainThread(MainThread, started 11744)>]
当前运行的线程数为:1
Process finished with exit code 0
这个地方看起来还是比较清晰的。
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据。缺点就是,线程是对全局变量随意篡改可能造成多线程之间对全局变量的混乱(即线程非安全)
一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。不仅可以通过线程完成多任务,进程也是可以的
# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
def run_proc():
"""子进程要执行的代码"""
while True:
print("----2----")
time.sleep(1)
if __name__=='__main__':
p = Process(target=run_proc)
p.start()
while True:
print("----1----")
time.sleep(1)
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
from multiprocessing import Pool
def show(num):
print('num : ' + str(num))
if __name__=="__main__":
pool = Pool(processes = 3)
for i in xrange(6):
# 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
pool.apply_async(show, args=(i, ))
print('====== apply_async ======')
pool.close()
#调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
pool.join()
多任务在什么语言中都是比较重要的概念,同时也都有很丰富的应用场景。不过刚开始接触python的时候,不是特别容易理解。做个简单的了解就行,用到的时候再去具体学习,千万不要被搞没积极性了!!!!!!
想学习python或者正在转行python相关的行业的朋友们可以进qq群798665505,群里有许多对python感兴趣的朋友,里面也有很多有趣的灵魂。同样你可以获得很多资料,大家一起学习。一起进步,身体和灵魂,总要有一个在路上。
当然,你也可以扫描二维码: