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


    认识进程与线程(python)

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

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

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

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

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

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

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

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

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

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

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

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

    调度算法:

    ​ 时间片轮转

    ​ 优先级调度

    3、并行需要的核心条件

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

    阶段二:多进程实现并行

    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()   # 启动线程
  • 相关阅读:
    JS 反射机制及 Reflect 详解
    React Hooks
    深入理解 React setState
    React 函数组件和类组件的区别
    tsconfig.json 编译器配置大全
    React TS 解决不声明变量类型时的报错问题
    JSX onClick 和 HTML onclick 的区别
    深入理解 ES6 Generator
    JS 算法与数据结构之队列
    深入理解 ES6 Proxy
  • 原文地址:https://www.cnblogs.com/zcmq/p/9886374.html
Copyright © 2020-2023  润新知