【4.0】知识点小结(线程进阶)

【4.0】知识点小结(线程进阶)

【一】什么是死锁与递归锁

  • 死锁是指两个或多个进程,在执行过程中,因争夺资源而造成了互相等待的一种现象。
    • 即两个或多个进程持有各自的锁并试图获取对方持有的锁,从而导致被阻塞,不能向前执行,最终形成僵局。
    • 在这种情况下,系统资源利用率极低,系统处于一种死循环状态。
  • 递归锁(也叫可重入锁)是一种特殊的锁,它允许一个线程多次请求同一个锁,称为“递归地”请求锁
    • 在该线程释放锁之前,会对锁计数器进行累加操作,线程每成功获得一次锁时,都要进行相应的解锁操作,直到锁计数器清零才能完全释放该锁。
    • 递归锁能够保证同一线程在持有锁时能够再次获取该锁,而不被自己所持有的锁所阻塞,从而避免死锁的发生。
    • 但是注意要正常使用递归锁,避免过多地获取锁导致性能下降。

【1】死锁

from threading import Thread, Lock
import time

metexA = Lock()
metexB = Lock()


# 类只要加括号多次 产生的肯定不同的对象
# 如果你想要实现多次加括号等到的是相同的对象 - 单例模式

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        metexA.acquire()
        # self.name:获取当前线程名
        print(f'{self.name} 抢到了A锁')
        metexB.acquire()
        print(f'{self.name} 抢到了B锁')
        metexB.release()
        metexA.release()

    def func2(self):
        metexB.acquire()
        # self.name:获取当前线程名
        print(f'{self.name} 抢到了A锁')
        time.sleep(2)
        metexA.acquire()
        print(f'{self.name} 抢到了B锁')
        metexA.release()
        metexB.release()


def main():
    for i in range(10):
        t = MyThread()
        t.start()


if __name__ == '__main__':
    main()
    
    # Thread-1 抢到了A锁
    # Thread-1 抢到了B锁
    # Thread-1 抢到了A锁
    # Thread-2 抢到了A锁
    # 线程卡死
    # 开启十个线程 第一个线程走完第一圈 回到原地抢 A 结果第二个线程已经拿到了A 导致AB卡死

【2】递归锁

可以被连续的 acquire 和 release

但是只能被第一个抢到这把锁上执行上述操作

他的内部有一个计数器,每acquire一次计数 +1 每release一次 计数-1

只要计数不为0,那么其他人都无法抢到该锁

from threading import Thread, Lock, RLock
import time

# 两个变量同时指向一把锁
metexA = metexB = RLock()


# 类只要加括号多次 产生的肯定不同的对象
# 如果你想要实现多次加括号等到的是相同的对象 - 单例模式

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        metexA.acquire()
        # self.name:获取当前线程名
        print(f'{self.name} 抢到了A锁')
        metexB.acquire()
        print(f'{self.name} 抢到了B锁')
        metexB.release()
        metexA.release()

    def func2(self):
        metexB.acquire()
        # self.name:获取当前线程名
        print(f'{self.name} 抢到了A锁')
        time.sleep(2)
        metexA.acquire()
        print(f'{self.name} 抢到了B锁')
        metexA.release()
        metexB.release()


def main():
    for i in range(10):
        t = MyThread()
        t.start()


if __name__ == '__main__':
    main()

    # Thread-1 抢到了A锁
    # Thread-1 抢到了B锁
    # Thread-1 抢到了A锁
    # Thread-1 抢到了B锁
    # Thread-2 抢到了A锁
    # Thread-2 抢到了B锁
    # Thread-2 抢到了A锁
    # Thread-2 抢到了B锁
    # Thread-4 抢到了A锁
    # Thread-4 抢到了B锁
    # Thread-4 抢到了A锁
    # 不会卡主正常进行

【二】信号量

  • 信号量在不同的阶段可能对应不同的技术点
  • 在并发编程中信号量指的是锁

如果我们将互斥锁比喻成一个厕所

那信号量就相当于多个厕所

【1】基础版 1.0

通过信号量限制线程抢的线程开设数

线程数是5 , 只能每次5个人一起抢,一起走

# -*-coding: Utf-8 -*-
# @File : 02 信号量 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from threading import Thread, Semaphore
import time
import random

# 参数:表示开设几个空位
sm = Semaphore(5)


def task(name):
    sm.acquire()
    print(f'{name} 正在使用')
    # 模拟延迟
    # time.sleep(random.randint(1, 5))
    time.sleep(3)
    sm.release()


def main():
    for i in range(10):
        t = Thread(target=task, args=(i,))
        t.start()


if __name__ == '__main__':
    main()

    # 0 正在使用
    # 1 正在使用
    # 2 正在使用
    # 3 正在使用
    # 4 正在使用
    # 
    # 5 正在使用
    # 7 正在使用
    # 6 正在使用
    # 9 正在使用
    # 8 正在使用
# -*-coding: Utf-8 -*-
# @File : 02 信号量 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from threading import Thread, Semaphore
import time
import random

# 参数:表示开设几个空位
sm = Semaphore(5)


def task(name):
    sm.acquire()
    print(f'{name} 正在使用')
    # 模拟延迟
    time.sleep(random.randint(1, 5))
    # time.sleep(3)
    sm.release()


def main():
    for i in range(20):
        t = Thread(target=task, args=(f'{i}玩家',))
        t.start()


if __name__ == '__main__':
    main()

    # 0 正在使用
    # 1 正在使用
    # 2 正在使用
    # 3 正在使用
    # 4 正在使用
    #
    # 5 正在使用
    # 7 正在使用
    # 6 正在使用
    # 9 正在使用
    # 8 正在使用

【三】Event事件

  • 一些进程/线程需要等待另外一些进程/线程运行完毕后才能运行,类似于发射信号一样
# -*-coding: Utf-8 -*-
# @File : 03 Event事件 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from threading import Thread, Event
import time

# 造了一个红绿灯
event = Event()


# 设置灯
def light(name):
    print(f'{name} 人:>>> red light')
    time.sleep(2)
    print(f'{name} 人:>>> green light')

    # 告诉等待红灯的人可以走了
    event.set()


def car(name):
    print(f'{name} 车:>>> 正在等红灯')

    # 等待别人的信号 :有人触发 .set() 这个方法 表示 .wait() 可以继续向下走
    event.wait()
    print(f'{name} 车:>>> 走了')


def main():
    t = Thread(target=light, args=('dream',))
    t.start()

    for i in range(20):
        t = Thread(target=car, args=('bud',))
        t.start()

if __name__ == '__main__':
    main()
    
    # dream 人:>>> red light
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # bud 车:>>> 正在等红灯
    # dream 人:>>> green light
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # bud 车:>>> 走了bud 车:>>> 走了
    # bud 车:>>> 走了bud 车:>>> 走了bud 车:>>> 走了
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # 
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # 
    # 
    # bud 车:>>> 走了
    # bud 车:>>> 走了bud 车:>>> 走了
    # 
    # bud 车:>>> 走了
    # bud 车:>>> 走了
    # bud 车:>>> 走了

【四】线程q

  • 同一个进程下的多个线程数据是共享的
  • 为什么在同一个进程下还要使用队列?
    • 因为队列 = 管道 + 锁
    • 使用队列是为了保证数据的安全

【1】后进先出 q

# -*-coding: Utf-8 -*-
# @File : 04 线程q .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26

import queue

# 我们现在使用的队列都是只能在本地测试使用

# 队列q:先进先出
'''
# 队列的常用方法
q = queue.Queue(3)
q.put(1)
q.get()
q.get_nowait()
q.get(timeout=3)
q.full()
q.empty()
'''

# (1)后进先出q
q = queue.LifoQueue(3)
q.put(1)
q.put(2)
q.put(3)

print(q.get())
# 3

【2】PriorityQueue设置队列优先级

数字越小优先级越高

import queue

# (2)优先级 q
# 可以给防止队列中的数据设置队列优先级
q = queue.PriorityQueue(3)
# (优先级,参数)
q.put((10, '111'))
q.put((100, '222'))
q.put((0, '333'))
q.put((-5, '444'))
print(q.get())

# (-5, '444')
# (优先级, 参数)
# 数字越小优先级越高

【五】进程池与线程池

【1】TCP实现并发的效果的原理

  • 没开设一个客户端

    • 就会有一个服务端服务
  • 服务端

# -*-coding: Utf-8 -*-
# @File : 05 进程池与线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26

from socket import *
from threading import Thread


def server_create(IP, PORT):
    server = socket()

    server.bind((IP, PORT))

    server.listen(5)

    while True:
        conn, addr = server.accept()
        t = Thread(target=conn_communication, args=(conn,))


def conn_communication(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:
                break
            print(data.decode('utf8'))
            conn.send(data.upper())
        except Exception as e:
            print(e)
            break
    conn.close()


def main():
    IP = '127.0.0.1'
    PORT = 8086
    t = Thread(target=server_create, args=(IP, PORT,))
    t.start()


if __name__ == '__main__':
    main()
  • 客户端
# -*-coding: Utf-8 -*-
# @File : 05 进程池与线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26

from socket import *


def client_create(IP, PORT):
    client = socket()

    client.connect((IP, PORT))

    while True:
        word = b'hello world'
        client.send(word)

        msg = client.recv(1024)
        print(msg)


if __name__ == '__main__':
    IP = '127.0.0.1'
    PORT = 8086

    client_create(IP, PORT)

无论是开设进程还是开设线程,都需要消耗资源

只不过开始线程消耗的资源比开始进程相对少一些

硬件的开发速度永远赶不上软件开发速度

我们的宗旨是保证计算机硬件正常工作的情况下最大程度的利用它

【2】池的概念

【1】什么是池?

  • 池是用来保证计算机硬件安全的情况下最大限度的利用计算机
  • 池降低了程序的运行效率,但是保证了计算机硬件的安全,从而保证程序的正常运行

【2】基础版 2.0

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数五倍数的线程数:可指定线程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个线程
# 这五个线程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个线程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ThreadPoolExecutor(5)


def task(n):
    print(n)
    time.sleep(2)


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            
'''


def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task

if __name__ == '__main__':
    normal()

【3】升级版 3.0

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数五倍数的线程数:可指定线程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个线程
# 这五个线程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个线程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ThreadPoolExecutor(5)


def task(n):
    print(n)
    time.sleep(2)


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            
'''


def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task


def many_steps():
    for i in range(20):
        pool.submit(task, i)
    print('this is a main task')
    # 0
    # 1
    # 2
    # 3
    # 4
    # this is a main task
    # 先执行五个子线程,再回到主线程


if __name__ == '__main__':
    many_steps()

【4】进阶版 4.0

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数五倍数的线程数:可指定线程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个线程
# 这五个线程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个线程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ThreadPoolExecutor(5)


def task(n):
    print(n)
    time.sleep(2)


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            
'''


def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task


def many_steps():
    for i in range(20):
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        print(f'这是 pool的返回值:>>>>{res.result()}') # None
        # 程序由并发变成了串行
        # 返回的结果是 None ---> 任务的返回结果 ----> 拿到了异步提交的返回结果
        # res.result() : 拿到的就是异步提交的任务的返回结果
    print('this is a main task')
    # 0这是 pool的返回值:>>>><Future at 0x1767f648a60 state=running>
    #
    # 1这是 pool的返回值:>>>><Future at 0x1767f7bce50 state=running>
    #
    # 2
    # 这是 pool的返回值:>>>><Future at 0x1767f7da220 state=running>
    # 3
    # 这是 pool的返回值:>>>><Future at 0x1767f7da5b0 state=running>
    # 4
    # 这是 pool的返回值:>>>><Future at 0x1767f7da940 state=running>
    # 这是 pool的返回值:>>>><Future at 0x1767f7dad30 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f7dae50 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f7daf70 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e10d0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e11f0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1310 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1430 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1550 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1670 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1790 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e18b0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e19d0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1af0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1c10 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x1767f9e1d30 state=pending>
    # this is a main task


if __name__ == '__main__':
    many_steps()

【5】迭代版 5.0

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数五倍数的线程数:可指定线程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个线程
# 这五个线程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个线程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ThreadPoolExecutor(5)


def task(n):
    print(n)
    time.sleep(2)


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            
'''


def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task


def many_steps():
    # 创建任务池子
    res_list = []
    for i in range(20):
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        res_list.append(res)
    for res in res_list:
        print(f'这是 pool的返回值:>>>>{res.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的
        
    print('this is a main task')
    # 0这是 pool的返回值:>>>><Future at 0x13bb6c68cd0 state=running>
    # 
    # 1
    # 这是 pool的返回值:>>>><Future at 0x13bb6df9100 state=running>
    # 2
    # 这是 pool的返回值:>>>><Future at 0x13bb6df9490 state=running>
    # 3
    # 这是 pool的返回值:>>>><Future at 0x13bb6df9820 state=running>
    # 4
    # 这是 pool的返回值:>>>><Future at 0x13bb6df9bb0 state=running>
    # 这是 pool的返回值:>>>><Future at 0x13bb6df9f70 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff100 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff220 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff340 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff460 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff580 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff6a0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff7c0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dff8e0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dffa00 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dffb20 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dffc40 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dffd60 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dffe80 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x13bb6dfffa0 state=pending>
    # 56
    # 7
    # 8
    # 9
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 101112
    # 13
    # 14
    # 
    # 
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 1516
    # 17
    # 18
    # 
    # 19
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # this is a main task



if __name__ == '__main__':
    many_steps()

【6】增强版 6.0 - pool.shutdown()

等待所有子线程结束后再打印程序运行结果

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数五倍数的线程数:可指定线程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个线程
# 这五个线程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个线程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ThreadPoolExecutor(5)


def task(n):
    print(n)
    time.sleep(2)

    return n*n


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            
'''


def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task


def many_steps():
    # 创建任务池子
    res_list = []
    for i in range(20):
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        res_list.append(res)

    # 关闭线程池 - 等待所有的线程池中的任务运行完毕
    pool.shutdown()
    for res in res_list:
        print(f'这是 pool的返回值:>>>>{res.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的

    print('this is a main task')
    # 1
    # 这是 pool的返回值:>>>><Future at 0x29bc36d91c0 state=running>
    # 2这是 pool的返回值:>>>><Future at 0x29bc36d9550 state=running>
    # 
    # 3
    # 这是 pool的返回值:>>>><Future at 0x29bc36d98e0 state=running>
    # 4
    # 这是 pool的返回值:>>>><Future at 0x29bc36d9c70 state=running>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de070 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de1c0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de2e0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de400 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de520 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de640 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de760 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de880 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36de9a0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36deac0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36debe0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36ded00 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36dee20 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36def40 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x29bc36e50a0 state=pending>
    # 5
    # 67
    # 
    # 8
    # 9
    # 10
    # 1112
    # 13
    # 
    # 14
    # 15
    # 1617
    # 1819
    # 
    # 
    # 这是 pool的返回值:>>>>0
    # 这是 pool的返回值:>>>>1
    # 这是 pool的返回值:>>>>4
    # 这是 pool的返回值:>>>>9
    # 这是 pool的返回值:>>>>16
    # 这是 pool的返回值:>>>>25
    # 这是 pool的返回值:>>>>36
    # 这是 pool的返回值:>>>>49
    # 这是 pool的返回值:>>>>64
    # 这是 pool的返回值:>>>>81
    # 这是 pool的返回值:>>>>100
    # 这是 pool的返回值:>>>>121
    # 这是 pool的返回值:>>>>144
    # 这是 pool的返回值:>>>>169
    # 这是 pool的返回值:>>>>196
    # 这是 pool的返回值:>>>>225
    # 这是 pool的返回值:>>>>256
    # 这是 pool的返回值:>>>>289
    # 这是 pool的返回值:>>>>324
    # 这是 pool的返回值:>>>>361
    # this is a main task



if __name__ == '__main__':
    many_steps()

【3】进程池的使用

【1】基础版 1.0

开设进程的进程 ID 号不会发生改变

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, os

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数 的进程 : 可指定进程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个进程
# 这五个进程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个进程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ProcessPoolExecutor(5)


def task(n):
    print(n, f'当前进程的进程号:>>>{os.getpid()}')
    time.sleep(2)

    return n * n


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            
'''


def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task ')

    # 1
    # this is a main task


def many_steps():
    # 创建任务池子
    res_list = []
    for i in range(20):
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        res_list.append(res)

    # 关闭线程池 - 等待所有的线程池中的任务运行完毕
    pool.shutdown()
    for res in res_list:
        print(f'这是 pool的返回值:>>>>{res.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的

    print('this is a main task')
    # 这是 pool的返回值:>>>><Future at 0x23ca907d460 state=running>
    # 这是 pool的返回值:>>>><Future at 0x23ca928b550 state=running>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6af0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f65e0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6940 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6a00 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6b20 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6ca0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6d30 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6e20 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6f70 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca92f6f40 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301220 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301340 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301310 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301550 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301670 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301760 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca93018b0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x23ca9301a00 state=pending>
    # 0 当前进程的进程号:>>>14680
    # 1 当前进程的进程号:>>>17936
    # 2 当前进程的进程号:>>>6028
    # 3 当前进程的进程号:>>>18332
    # 4 当前进程的进程号:>>>19176
    # 5 当前进程的进程号:>>>14680
    # 6 当前进程的进程号:>>>17936
    # 7 当前进程的进程号:>>>6028
    # 8 当前进程的进程号:>>>18332
    # 9 当前进程的进程号:>>>19176
    # 10 当前进程的进程号:>>>14680
    # 11 当前进程的进程号:>>>17936
    # 12 当前进程的进程号:>>>6028
    # 13 当前进程的进程号:>>>18332
    # 14 当前进程的进程号:>>>19176
    # 15 当前进程的进程号:>>>14680
    # 16 当前进程的进程号:>>>17936
    # 17 当前进程的进程号:>>>6028
    # 18 当前进程的进程号:>>>18332
    # 19 当前进程的进程号:>>>19176
    # 这是 pool的返回值:>>>>0
    # 这是 pool的返回值:>>>>1
    # 这是 pool的返回值:>>>>4
    # 这是 pool的返回值:>>>>9
    # 这是 pool的返回值:>>>>16
    # 这是 pool的返回值:>>>>25
    # 这是 pool的返回值:>>>>36
    # 这是 pool的返回值:>>>>49
    # 这是 pool的返回值:>>>>64
    # 这是 pool的返回值:>>>>81
    # 这是 pool的返回值:>>>>100
    # 这是 pool的返回值:>>>>121
    # 这是 pool的返回值:>>>>144
    # 这是 pool的返回值:>>>>169
    # 这是 pool的返回值:>>>>196
    # 这是 pool的返回值:>>>>225
    # 这是 pool的返回值:>>>>256
    # 这是 pool的返回值:>>>>289
    # 这是 pool的返回值:>>>>324
    # 这是 pool的返回值:>>>>361
    # this is a main task



if __name__ == '__main__':
    many_steps()

【2】进阶版 2.0 - add_done_callback(call_back)

add_done_callback(call_back) 返回值正是我们的上面 pool的返回的结果

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, os

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数 的进程 : 可指定进程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个进程
# 这五个进程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个进程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ProcessPoolExecutor(5)


def task(n):
    print(n, f'当前进程的进程号:>>>{os.getpid()}')
    time.sleep(2)

    return n * n


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            异步提交任务的返回结果 应该通过回调机制来获取
        异步回调机制?
            就相当于给每个异步任务绑定了一个定时炸弹
            一旦任务有结果会立即触发爆炸
'''


def call_back(n):
    print(f'call_back>>>:{n}')


def normal():

    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task ')

    # 1
    # this is a main task


def many_steps():
    # 创建任务池子
    res_list = []
    for i in range(20):
        # 继续添加异步回调方法
        res = pool.submit(task, i).add_done_callback(call_back)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        # res_list.append(res)

    """
    # 关闭线程池 - 等待所有的线程池中的任务运行完毕
    pool.shutdown()
    for res in res_list:
        print(f'这是 pool的返回值:>>>>{res.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的

    print('this is a main task')
    """
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 0 当前进程的进程号:>>>17524
    # 1 当前进程的进程号:>>>10136
    # 2 当前进程的进程号:>>>5420
    # 3 当前进程的进程号:>>>3932
    # 4 当前进程的进程号:>>>17644
    # call_back>>>:<Future at 0x27b365622e0 state=finished returned int>
    # 5 当前进程的进程号:>>>17524
    # 6 当前进程的进程号:>>>5420
    # call_back>>>:<Future at 0x27b367db370 state=finished returned int>
    # 7 当前进程的进程号:>>>10136
    # call_back>>>:<Future at 0x27b3656d3d0 state=finished returned int>
    # 8 当前进程的进程号:>>>3932
    # call_back>>>:<Future at 0x27b367db610 state=finished returned int>
    # 9 当前进程的进程号:>>>17644
    # call_back>>>:<Future at 0x27b367db760 state=finished returned int>
    # 10 当前进程的进程号:>>>17524
    # call_back>>>:<Future at 0x27b367db4f0 state=finished returned int>
    # 1211  当前进程的进程号:>>>5420当前进程的进程号:>>>10136
    # 
    # call_back>>>:<Future at 0x27b367db910 state=finished returned int>
    # call_back>>>:<Future at 0x27b367dbac0 state=finished returned int>
    # 13 当前进程的进程号:>>>3932
    # call_back>>>:<Future at 0x27b367dbbb0 state=finished returned int>
    # call_back>>>:<Future at 0x27b367dbca0 state=finished returned int>
    # 14 当前进程的进程号:>>>17644
    # 15 当前进程的进程号:>>>17524
    # call_back>>>:<Future at 0x27b367dbdf0 state=finished returned int>
    # 16 当前进程的进程号:>>>5420
    # 17 当前进程的进程号:>>>10136
    # call_back>>>:<Future at 0x27b367e2070 state=finished returned int>
    # call_back>>>:<Future at 0x27b367dbf10 state=finished returned int>
    # 18 当前进程的进程号:>>>3932
    # call_back>>>:<Future at 0x27b367e2190 state=finished returned int>
    # 19 当前进程的进程号:>>>17644
    # call_back>>>:<Future at 0x27b367e22b0 state=finished returned int>
    # call_back>>>:<Future at 0x27b367e23d0 state=finished returned int>
    # call_back>>>:<Future at 0x27b367e24f0 state=finished returned int>
    # call_back>>>:<Future at 0x27b367e2610 state=finished returned int>
    # call_back>>>:<Future at 0x27b367e2730 state=finished returned int>
    # call_back>>>:<Future at 0x27b367e2850 state=finished returned int>
    # 
    # Process finished with exit code 0


if __name__ == '__main__':
    many_steps()

【3】升级版 - 3.0

# -*-coding: Utf-8 -*-
# @File : 06 进程池和线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, os

# (1)线程池
# (1.1)参数详解
# 默认开设当前计算机 cpu 个数 的进程 : 可指定进程数
# (1.2)原理详解
# 池子造出来后 里面固定存在五个进程
# 这五个进程不会存在出现重复创建和销毁的过程
# (1.3)优点
# 避免了重复创建五个进程的资源开销
# (1.4)使用方法
# 构造好池子以后,只需要将需要做的任务向池子中提交即可
pool = ProcessPoolExecutor(5)


def task(n):
    print(n, f'当前进程的进程号:>>>{os.getpid()}')
    time.sleep(2)

    return n * n


# 向池子中提交任务
'''
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果,期间不做任何事
    异步:提交任务之后不等待任务的返回结果,继续执行代码
        返回结果如何获取?
            异步提交任务的返回结果 应该通过回调机制来获取
        异步回调机制?
            就相当于给每个异步任务绑定了一个定时炸弹
            一旦任务有结果会立即触发爆炸
'''


def call_back(n):
    # 这里的n是对象
    print(f'call_back>>>:{n}返回的结果{n.result()}')


def normal():

    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task ')

    # 1
    # this is a main task


def many_steps():
    # 创建任务池子
    res_list = []
    for i in range(20):
        # 继续添加异步回调方法
        res = pool.submit(task, i).add_done_callback(call_back)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        # res_list.append(res)

    """
    # 关闭线程池 - 等待所有的线程池中的任务运行完毕
    pool.shutdown()
    for res in res_list:
        print(f'这是 pool的返回值:>>>>{res.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的

    print('this is a main task')
    """
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 0 当前进程的进程号:>>>11484
    # 1 当前进程的进程号:>>>5068
    # 2 当前进程的进程号:>>>20224
    # 3 当前进程的进程号:>>>16524
    # 4 当前进程的进程号:>>>14784
    # 5 当前进程的进程号:>>>11484
    # call_back>>>:<Future at 0x1c2f98322e0 state=finished returned int>返回的结果0
    # 6 当前进程的进程号:>>>5068
    # call_back>>>:<Future at 0x1c2f983d3d0 state=finished returned int>返回的结果1
    # 7 当前进程的进程号:>>>20224
    # 8 当前进程的进程号:>>>16524
    # call_back>>>:<Future at 0x1c2f98ab370 state=finished returned int>返回的结果9
    # call_back>>>:<Future at 0x1c2f98ab3a0 state=finished returned int>返回的结果4
    # 9 当前进程的进程号:>>>14784
    # call_back>>>:<Future at 0x1c2f98ab760 state=finished returned int>返回的结果16
    # 10 当前进程的进程号:>>>11484
    # 11 当前进程的进程号:>>>5068
    # call_back>>>:<Future at 0x1c2f98ab580 state=finished returned int>返回的结果25
    # call_back>>>:<Future at 0x1c2f98ab910 state=finished returned int>返回的结果36
    # 12 当前进程的进程号:>>>20224
    # 13 当前进程的进程号:>>>16524
    # call_back>>>:<Future at 0x1c2f98ab940 state=finished returned int>返回的结果49
    # call_back>>>:<Future at 0x1c2f98abbb0 state=finished returned int>返回的结果64
    # 14 当前进程的进程号:>>>14784
    # call_back>>>:<Future at 0x1c2f98abd00 state=finished returned int>返回的结果81
    # 15 当前进程的进程号:>>>11484
    # 16 当前进程的进程号:>>>5068
    # call_back>>>:<Future at 0x1c2f98abdf0 state=finished returned int>返回的结果100
    # call_back>>>:<Future at 0x1c2f98abf40 state=finished returned int>返回的结果121
    # 17 当前进程的进程号:>>>16524
    # 18 当前进程的进程号:>>>20224
    # call_back>>>:<Future at 0x1c2f98b2070 state=finished returned int>返回的结果144
    # call_back>>>:<Future at 0x1c2f98b21c0 state=finished returned int>返回的结果169
    # 19 当前进程的进程号:>>>14784
    # call_back>>>:<Future at 0x1c2f98b22b0 state=finished returned int>返回的结果196
    # call_back>>>:<Future at 0x1c2f98b24f0 state=finished returned int>返回的结果256
    # call_back>>>:<Future at 0x1c2f98b23d0 state=finished returned int>返回的结果225
    # call_back>>>:<Future at 0x1c2f98b2700 state=finished returned int>返回的结果324
    # call_back>>>:<Future at 0x1c2f98b25e0 state=finished returned int>返回的结果289
    # call_back>>>:<Future at 0x1c2f98b2850 state=finished returned int>返回的结果361
    # 
    # Process finished with exit code 0


if __name__ == '__main__':
    many_steps()

【4】总结

# 导入模块
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 构建池子
pool = ProcessPoolExecutor(5)

# 提交任务
pool.submit(task, i).add_done_callback(call_back)

【六】协程

  • 进程

    • 资源单位
  • 线程

    • 执行单位
  • 协程

    • 假想存在概念:单线程下实现并发的效果
    • 在代码层面上监控所有的 IO 操作,一旦遇到 IO 就在代码层级完成切换
    • 让CPU一直运行,没有IO,从而提升程序的运行效率
  • 多道技术

    • 切换 + 并发状态

      • 切换不一定是提升效率,也可能是降低效率

      • IO 切换:提升效率

      • 无IO 切换:降低效率

    • 代码如何实现?

      • 保存上一次的执行状态,下一次继续执行
        • yield 方法(保存状态)
  • CPU切换的状态

    • 程序遇到IO
    • 程序长时间占用

【1】验证切换是否一定提升效率?

【1】基础版 - 1.0

最原始的计算方式:串行

# -*-coding: Utf-8 -*-
# @File : 07 协程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
import time


def func1():
    for i in range(100000000):
        i += 1


def func2():
    for i in range(100000000):
        i += 1


def normal():
    func1()
    func2()


def main():
    start_time = time.time()
    normal()
    print(f'总耗时{time.time() - start_time}')
    # 总耗时10.284734964370728


if __name__ == '__main__':
    main()

【2】升级版 - 2.0

切换 + yield --- 时间变长

# -*-coding: Utf-8 -*-
# @File : 07 协程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
import time


def func1():
    while True:
        100000000 + 1
        yield


def func2():
    # 初识化迭代生成器
    g = func1()
    for i in range(100000000):
        i + 1
        # 调用迭代生成器
        next(g)


def normal():
    func1()
    func2()


def theGenerator():
    func2()


def main():
    start_time = time.time()
    theGenerator()
    print(f'总耗时{time.time() - start_time}')
    # 总耗时15.642895460128784


if __name__ == '__main__':
    main()

【3】增强版 - 3.0 - gevent模块

  • 基础版 - 单线程操作
# -*-coding: Utf-8 -*-
# @File : 07 协程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
import time
import gevent


def hello_me():
    print(f'hello you')
    time.sleep(3)
    print(f'hello you')


def hello_you():
    print(f'hello me')
    time.sleep(2)
    print(f'hello me')


def run():
    hello_me()
    hello_you()


def main():
    start_time = time.time()
    run()
    print(f'总耗时{time.time() - start_time}')
    # hello you
    # hello you
    # hello me
    # hello me
    # 总耗时5.00632119178772


if __name__ == '__main__':
    main()
  • 升级版 - 多线程 - 切换 IO

程序运行的时间取自运行时间最长的那个

# -*-coding: Utf-8 -*-
# @File : 07 协程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26
import time
from gevent import spawn
from gevent import monkey

monkey.patch_all()

'''
gevent : 无法检测常见的 IO 操作,只能检测自己的 IO 操作

如果想检测 其他 IO 需要加上一句
from gevent import monkey
monkey.patch_all()

又由于上面的代码在使用 gevent 模块的时候是必须导入的,所以支持简写
from gevent import monkey;monkey.patch_all()

'''


def hello_me():
    print(f'hello you')
    time.sleep(3)
    print(f'hello you')


def hello_you():
    print(f'hello me')
    time.sleep(2)
    print(f'hello me')


def run():
    g1 = spawn(hello_me)
    g2 = spawn(hello_you)

    # 等待被检测的任务执行完毕再向下进行
    g1.join()
    g2.join()


def main():
    start_time = time.time()
    run()
    print(f'总耗时{time.time() - start_time}')

    # 当程序遇到 IO 时 会立马切换到没有 IO 的进程上
    # hello you
    # hello me
    # hello me
    # hello you
    # 总耗时3.0524613857269287


if __name__ == '__main__':
    main()

【2】协程实现 TCP 高并发效果

  • 服务端
# -*-coding: Utf-8 -*-
# @File : 05 进程池与线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26

from socket import *
from threading import Thread
from gevent import monkey

monkey.patch_all()
from gevent import spawn


def server_create(IP, PORT):
    server = socket()

    server.bind((IP, PORT))

    server.listen(5)

    while True:
        conn, addr = server.accept()
        spawn(conn_communication, conn)


def conn_communication(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:
                break
            print(data.decode('utf8'))
            conn.send(data.upper())
        except Exception as e:
            print(e)
            break
    conn.close()


def main():
    IP = '127.0.0.1'
    PORT = 8086
    g1 = spawn(server_create, IP, PORT)
    g1.join()


if __name__ == '__main__':
    main()

  • 客户端
# -*-coding: Utf-8 -*-
# @File : 05 进程池与线程池 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/26

from socket import *
from threading import Thread, current_thread


def client_create(IP, PORT):
    count = 0
    client = socket()

    client.connect((IP, PORT))

    while True:
        msg = f'{count} is running  {current_thread().name}'
        count += 1
        client.send(msg.encode('utf8'))

        msg = client.recv(1024)
        print(msg.decode('utf8'))


def main():
    IP = '127.0.0.1'
    PORT = 8086
    for i in range(100)
        t = Thread(target=client_create, args=(IP, PORT,))
        t.start()


if __name__ == '__main__':
    main()

【七】总结

  • 我们可以通过多进程下面开设多线程
    • 再通过多线程下面开设协程
  • 达到提升程序的执行效率
posted @ 2023-06-26 17:45  Chimengmeng  阅读(14)  评论(0编辑  收藏  举报