进程线程和协程二

前言

上面那篇文章我们提到了线程和锁的一些概念,但是代码有些冗余,比如需要我手动执行start,手动执行join,子线程数量少还好,如果多起来的话,就会显得代码很呆,因此引出下一个概念-->线程池(ThreadPoolExecutor)

线程池-submit版本

示例代码

python 复制代码
from concurrent.futures import ThreadPoolExecutor
from threading import Thread, Lock
import time

total_money = 200

l = Lock()

def speed_money(name: str, sp_money: int):
    time.sleep(1)
    with l:
        global total_money
        print(f"\n当前线程是{name},准备取{sp_money}元,开始检测余额是否充足")
        if total_money:
            time.sleep(1)  # 只是增加了这步
            print(f"\n当前线程是{name},余额充足为{total_money},开始取钱")
            total_money = round(total_money - sp_money, 2)
            print(f"\n当前线程是{name},已经取了{sp_money},账号余额{total_money}")
    return total_money

def main():
    # 构建线程
    with ThreadPoolExecutor() as executor:
        e1 = executor.submit(speed_money, "第一个线程", 100)
        e2 = executor.submit(speed_money, "第二个线程", 100)
        e3 = executor.submit(speed_money, "第三个线程", 100)

    print("\ne1,e2,e3都submit了~~~~~")
    print("\n开始依次获取执行结果")
    print(e1.result())
    print(e2.result())
    print(e3.result())
    print("\ne1,e2,e3都result完了,")

if __name__ == '__main__':
    start_time = time.time()
    main()
    print("\nmain函数执行结束")
    end_time = time.time()
    print("\n总耗时", round(end_time - start_time, 2))

执行结果

我们可以看到 在submit的时候,3个子线程就依次启动了,并且是没有阻塞主线程的,然后在子线程获取result的发现主线程是又被阻塞的 因此得出

结论

  • 线程池submit和线程Thread的start很像(ps都是启动子线程,并且不会阻塞主线程)
  • 线程池result和线程Thread的join很像(ps都是阻塞主线程,直到子线程执行完)
  • 不同点是result是会获取子线程的结果的,但是join不行

线程池-map版本

示例代码

python 复制代码
from concurrent.futures import ThreadPoolExecutor
from threading import Thread, Lock
import time

total_money = 200

l = Lock()

def speed_money(name: str, sp_money: int):
    time.sleep(1)
    with l:
        global total_money
        print(f"\n当前线程是{name},准备取{sp_money}元,开始检测余额是否充足")
        if total_money:
            time.sleep(1)  # 只是增加了这步
            print(f"\n当前线程是{name},余额充足为{total_money},开始取钱")
            total_money = round(total_money - sp_money, 2)
            print(f"\n当前线程是{name},已经取了{sp_money},账号余额{total_money}")
    return total_money

def main():
    # 构建线程
    with ThreadPoolExecutor() as executor:
        results = executor.map(
            speed_money,
            ["第一个线程", "第二个线程", "第三个线程"],  # speed_money接受的传入第一个参数的可迭代对象
            [100, 100, 100]  # speed_money接受的传入第二个参数的可迭代对象
        )

    print("\ne1,e2,e3开始map了~~~~~")
    print("\n开始依次获取执行结果")
    for result in results:
        print("\n result", result)

    print("\ne1,e2,e3都map完了,")

if __name__ == '__main__':
    start_time = time.time()
    main()
    print("\nmain函数执行结束")
    end_time = time.time()
    print("\n总耗时", round(end_time - start_time, 2))

执行结果

通过结果可以发现,基本上和submit打印的都是一样的,所以说数据也是没问题的,但是相较于submit的话,map就很通用了,使用方式和普通的map保持一致,也是在map的时候子线程就会执行,执行完得到的是一个可迭代对象,需要使用for或者next来获取子线程的返回值

map和submit的区别

相关推荐
焗猪扒饭7 小时前
redis stream用作消息队列极速入门
redis·后端·go
树獭非懒7 小时前
AI大模型小白手册|Embedding 与向量数据库
后端·python·llm
IT_陈寒10 小时前
SpringBoot实战:5个让你的API性能翻倍的隐藏技巧
前端·人工智能·后端
梦想很大很大10 小时前
拒绝“盲猜式”调优:在 Go Gin 项目中落地 OpenTelemetry 链路追踪
运维·后端·go
唐叔在学习11 小时前
就算没有服务器,我照样能够同步数据
后端·python·程序员
用户685453759776911 小时前
同步成本换并行度:多线程、协程、分片、MapReduce 怎么选才不踩坑
后端
javaTodo12 小时前
Claude Code 记忆机制详解:从 CLAUDE.md 到 Auto Memory,六层体系全拆解
后端
LSTM9712 小时前
使用 C# 和 Spire.PDF 从 HTML 模板生成 PDF 的实用指南
后端
JaguarJack12 小时前
为什么 PHP 闭包要加 static?
后端·php·服务端