欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

12 认识进程与线程 (进阶)

程序员文章站 2022-04-04 09:50:42
认识进程与线程(python) 一段时间没有更新博客了,今天和大家讲讲关于 python 进程和线程的知识点。(个人心得,多多指教!) 阶段一:并发与并行的深入理解 ​ 并行一定是并发,但并发不一定是并行。 ​ 并行是相对的,并行是绝对的。 问题一: 计算机是如何执行程序指令的? 问题二: 计算机如 ......

认识进程与线程(python)

  一段时间没有更新博客了,今天和大家讲讲关于 python 进程和线程的知识点。(个人心得,多多指教!)

阶段一:并发与并行的深入理解

​ 并行一定是并发,但并发不一定是并行。

​ 并行是相对的,并行是绝对的。

1、关于并行与并发的问题引入:

问题一: 计算机是如何执行程序指令的?

问题二: 计算机如何模拟出并行执行的效果?

问题三: 真正的并行需要依赖什么?

2、计算机执行指令示意图

12 认识进程与线程 (进阶)

12 认识进程与线程 (进阶)

2、轮询调度实现并发执行

并发:看上去一起执行,同时在发生

并行:真正一起执行,同时在进行

调度算法:

​ 时间片轮转

​ 优先级调度

12 认识进程与线程 (进阶)

3、并行需要的核心条件

​ 并行真正的核心条件是有多个cpu

12 认识进程与线程 (进阶)

阶段二:多进程实现并行

1、多进程并行问题引入

问题一: 什么是进程?

问题二: 如何在python中使用进程?

问题三: 多进程实现并行的必要条件是什么?

2、进程的概念

计算机程序是存储在磁盘上的可执行二进制(或其他类型)文件。

​ 只有把它们加载到内存中,并被操作系统调用它们才会拥有其自己的生命周期。

进程则是表示的一个正在执行的程序。

​ 每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据

操作系统负责其上所有进程的执行。

​ 操作系统会为这些进程合理地分配执行时间。

3、在python中直接执行耗时函数
import time
​
print('main-task start:', time.asctime(time.localtime(time.time())))
​
def func():
    print('sub-task start:', time.asctime(time.localtime(time.time())))
    time.sleep(5)
    print('sub-task end:', time.asctime(time.localtime(time.time())))
​
func()
time.sleep(5)
print('main-task end:', time.asctime(time.localtime(time.time())))
4、在python中使用进程来分担耗时任务
import time
import multiprocessing
​
def func(n):
    for i in range(n):
        for a in range(n):
            for b in range(n):
                print(b)
​
start_time = time.time()
​
p = multiprocessing.process(target=func, args=(50, ))    # 实例化,创建一个进程
# 参数如何传?  args=(50, )  kwargs={'n': 50}
p.start()   # 开启进程
p.join()    # 主进程等待子进程结束
​
func(50)
# func(50)
​
end_time = time.time()
print('运行了%ds!' % (end_time - start_time))
5、多进程并行的必要条件

总进程数量不多于cpu核心数量!

​ 因此,现在运行的程序都是轮询调度产生的并行假象。但是在python层面的确获得了并行!

阶段三:多线程实现并发

1、多线程并发问题引入

问题一: 什么是线程?

问题二: 如何在python中使用线程?

问题三: 为什么多线程不是并行?

2、线程的概念

线程被称作轻量级进程。

​ 与进程类似,不过它们是在同一个进程下执行的。并且它们会共享相同的上下文。

当其他线程运行时,它可以被抢占(中断)和临时挂起(也成为睡眠)— 让步

​ 线程的轮询调度机制类似于进程的轮询调度。只不过这个调度不是由操作系统来负责,而是由python解释器来负责。

3、在python中使用线程来避开阻塞任务
import time
import multiprocessing
import threading
​
print('---outer--start---:', time.asctime(time.localtime(time.time())))
​
def func():
    print('---inner--start---:', time.asctime(time.localtime(time.time())))
    time.sleep(5)
    print('---inner--end---:', time.asctime(time.localtime(time.time())))
​
"""
在进程里可以模拟耗时任务,但是在线程里只能模拟阻塞任务,不能模拟耗时任务。因为多线程只有一个核心进程。
"""
p = multiprocessing.process(target=func)    # 创建子进程
t = threading.thread(target=func)   # 创建子线程
t.start()   # 开启子线程
​
time.sleep(5)
print('---outer--end---:', time.asctime(time.localtime(time.time())))

cpu在任意一个进程里,任意时刻,只能执行一个线程

​ 对进程的轮询是操作系统负责调度

​ 对线程的轮询是python解释器负责调度

4、gil锁 全局解释器锁

python在设计的时候,还没有多核处理器的概念。

因此,为了设计方便与线程安全,直接设计了一个锁。

这个锁要求,任何进程中,一次只能有一个线程在执行。

因此,并不能为多个线程分配多个cpu。

所以python中的线程只能实现并发,

而不能实现真正的并行。

但是python3中的gil锁有一个很棒的设计,

在遇到阻塞(不是耗时)的时候,会自动切换线程。

5、gil锁带给我们的新认知

遇到阻塞就自动切换。因此我们可以利用这种机制来有效的避开阻塞~充分利用cpu

阶段四:使用多进程与多线程来实现并发服务器

关键点一: 多进程是并行执行,

​ 相当于分别独立得处理各个请求。

关键点二: 多线程,虽然不能并行运行,

​ 但是可以通过避开阻塞切换线程

​ 来实现并发的效果,并且不浪费cup

from socket import *
from multiprocessing import process     # 进程
from threading import thread    # 线程
​
# 创建套接字
server = socket()
server.bind(('', 9999))
server.listen(1000)
​
# 定义函数
def func(conn):
    while true:
        recv_data = conn.recv(1024)
        if recv_data:
            print(recv_data)
            conn.send(recv_data)
        else:
            conn.close()
            break
​
​
while true:   # 循环去监听
    conn, addr = server.accept()
    # 每生成一个对等连接套接字,我就生成一个进程、线程,并且我让这个进程、线程去服务这个连接过来的客户端
​
    # p = process(target=func, args=(conn, ))    # 生成一个进程
    # p.start()   # 启动进程
​
​
    t = thread(target=func, args=(conn, ))    # 生成一个线程
    t.start()   # 启动线程