1、线程,进程是什么,协程是什么
-
线程和进程都是操作系统里的概念
-
进程:进程是操作系统进行资源分配和调度的基本单位。可以把进程想象成一个独立的工作区域,里面包含了程序运行所需的所有资源,比如内存、文件、设备等。每个进程都有自己的地址空间,所以它们之间是相互独立的。比如电脑上打开谷歌浏览器,操作系统就会去使用进程运行。
-
线程:进程是一个独立的工作区域,线程就是这个工作区域的员工,负责更具体的工作内容。同一个进程内的多个线程共享该进程的地址空间和其他资源,所以它们之间的通信和数据共享相对简单。线程就是进程里的面的一个执行单元,只能包含在进程中。
-
协程(coroutine):python中协程是线程里的一部分,可以理解为一个微型的线程,如下图。
小结:线程是进程里的,协程是线程里的。进程向操作系统去申请一个独立的资源。线程在进程里,去调度进程申请到的资源。
2、多进程和多线程
1、当你在电脑上,同时打开浏览器开启一个网页,和游戏的时候,就是开启了多任务,这个是通过多进程是实现的。然后 你的浏览器的进程具体是内部的去用多线程去实现的,,而在每个线程内部,可能会使用协程(coroutines)来进一步提高执行效率。
进程:进程和进程之间,资源不共享
线程:线程是操作系统进行调度的最小单位,线程因为是进程内部的一个单元,所以,一个进程内部的线程和线程是资源共享的。
协程: 协程是线程内部的一个单元,一个线程内部的协程,协程和协程之间,共享这个线程内部的资源
听起来,线程和协程是一样的。
区别在于,一个进程内部的线程资源虽然是共享的,但是线程之间调用的话,因为是操作系统调度的,需要切换上下文信息,这个很浪费时间,但是协程共享线程的资源是不需要切换的。并且协程的切换是由编程者控制的,因此可以减少无效的调度,提高执行效率。(可以搜一下,什么是上下文信息管理,以及协程之间切换的步骤)
3、线程和多线程的实现
在Python中如果想使用线程实现多任务,可以使用thread模块 但是它比较底层,即意味着过程较为复杂不方便使用;推荐使用threading模块,它是对thread做了一些包装的,可以更加方便使用
3.1如果不用多线程,只是单线程运行
import time
def say_hello():
print("今天又是美好的一天")
time.sleep(1)
for i in range(5):
say_hello()
3.2使用多线程
import threading
import time
def say_hello():
print("今天又是美好的一天")
time.sleep(1)
for i in range(5):
t = threading.Thread(target=say_hello)
t.start() # 启动线程,即让线程开始执行
分别运行上面两个程序,观察运行的结果
- 可以明显看出使用了多线程并发的操作,花费时间要短很多
- 当调用start()时,才会真正的创建线程,并且开始执行
3.3 同时执行多个不同的任务
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)
print('---开始---:%s' % ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
sleep(5) # 屏蔽此行代码,试试看,程序是否会立马结束?
print('---结束---:%s' % ctime())
小结:
如果在一个程序中需要有多个任务一起执行,可以将每个任务单独放到一个函数中
使用threading.Thread创建一个对象,注意实参target需要指定为刚刚定义的函数名(不要写上小括号,那表示调用函数了)
调用threading.Thread返回的对象中的start方法(会让这个线程开始运行)
主线程会等待所有的子线程结束后才结束,所以当屏蔽sleep(5) 这一行,虽然 print(‘—结束—:%s’ % ctime()) 这一句执行完了,还是会等前面的线程执行完成才终止这个程序。
3.4 多线程执行的顺序不确定
import threading
from time import sleep, ctime
def test1():
"""
这是一个单独的任务
"""
for i in range(10):
print("任务1...%d" % i)
sleep(0.1)
def test2():
"""
这是另外一个单独的任务
"""
for i in range(5):
print("任务2...%d" % i)
sleep(0.2)
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
小结:
当python程序中有多个任务需要被执行时,这些任务需要等待操作系统的调度(即操作系统安排接下来要执行哪个任务),因为每次运行程序时的环境(例如上次运行时 除了这个python程序之外还有QQ、微信在运行,而这次运行时没有QQ只有微信在运行都会影响操作系统的调度策略)不一样,所以多次运行同一个python程序时任务执行的先后顺序是不同的
3.5查看线程数量(了解)
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)
print('---开始---:%s' % ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
while True:
# threading.enumerate()能够得到当前这个程序中正在运行的所有任务,是一个列表
length = len(threading.enumerate())
print('当前运行的线程数为:%d' % length)
if length <= 1:
break
# 延时一会,等等其他线程执行
sleep(0.5)
小结:
使用threading.enumerate()能够得到当前程序在运行时,所有的线程信息,以列表的方式返回
我们可以让主线程(程序运行后的默认线程),判断threading.enumerate()返回的线程数量,如果只有1个线程,那么就表示当前主线程自己,意味着没有其他的子线程(使用threading创建的那些线程),此时就可以结束主线程,只要主线程结束 那么这个程序也就结束了
4、进程和多进程的实现
线程是用的是threading这个模块,进程使用的是process这个模块
单进程:
如果我们不创建新的进程,单独运行一个代码,就是一个单进程,只有使用process这个模块去生成其余的进程,就是多进程了。
多进程代码的实现:
from multiprocessing import Process
import time
def test():
"""子进程单独执行的代码"""
while True:
print('---test---')
time.sleep(1)
if __name__ == '__main__':
p=Process(target=test)
p.start()创建一个子进程,开始运行上面的test这个函数
# 主进程单独执行的代码
while True:
print('---main---')
time.sleep(1)
小结:
1、 通过额外创建一个进程,可以实现多任务
2、使用进程实现多任务的流程:
- 创建一个Process对象,且在创建时通过target指定一个函数的引用
- 当调用start时,会真正的创建一个子进程,然后运行上面target指定的函数
3、 Process创建的实例对象的常用方法
- start():启动子进程实例(创建子进程)
- is_alive():判断子进程是否还在活着
- join([timeout]):是否等待子进程执行结束,或等待多少秒
- terminate():不管任务是否完成,立即终止子进程