进程线程和协程二

前言

上面那篇文章我们提到了线程和锁的一些概念,但是代码有些冗余,比如需要我手动执行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的区别

相关推荐
阳光是sunny8 小时前
LangGraph中的Reducer是什么
前端·人工智能·后端
灯澜忆梦8 小时前
GO_并发编程---定时器
开发语言·后端·golang
阳光是sunny8 小时前
从链到图:LangGraph 入门基础全解析
前端·人工智能·后端
皮皮林5519 小时前
开源实力派,给本地 AI 装上深度调研能力,一张 3090 跑到 95.7 分!
后端
努力的小雨9 小时前
把 Windows 桌面图标做成一个会自己运转的小世界
后端
武子康10 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
腾渊信息科技公司10 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
IT_陈寒12 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学12 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
码事漫谈12 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端