利用做饭的流程来解释多线程的应用

注意
本文最后更新于 2023-07-30,文中内容可能已过时。

单线程 & 单人做饭

单人做饭的流程 (我的流程

  1. 选择吃什么
  2. 买菜,买肉
  3. 做米饭
  4. 洗肉(解冻肉),洗菜,择菜。
  5. 切肉
  6. 切菜, 切辣椒,葱花,姜片。
  7. 炸肉,下花椒八角, 老抽,醋
  8. 把肉盛出来 (或者不盛)
  9. 下葱姜, 炒香后下辣椒
  10. 下蔬菜
  11. 放调味料
  12. 关火, 盛出来
  13. 盛米饭,吃饭

单线程

这里假定任务是处理一个玩家购买金币的 socket 请求

  1. 获取网络数据
  2. 解析成我们需要的数据格式
  3. 从数据库/缓存取出玩家信息
  4. 对玩家数据进行上锁
  5. 获取配置表数据 (花多少钻石可以购买多少金币
  6. 检测玩家的钻石是否足够
  7. 修改钻石和金币的数量
  8. 保存玩家的数据到数据库/缓存, 并解锁玩家数据
  9. 产生响应结果
  10. 发送数据给客户端

多线程 & 餐馆做饭

餐馆做饭

根据职责进行人员的分配,配合整个做菜流程

按职责分成下面几个角色。

  • 采购员
  • 案板
  • 打杂
  • 厨师
  • 服务员
  • 客人

每个角色的职责大致如下。

  • 采购员 (买菜,买肉
  • 案板 (切菜, 切肉
  • 打杂 (做米饭,配菜,送菜给服务员,拿盘子等
  • 厨师 (炒菜
  • 服务员 (把菜从厨房间端到客人面前,给客人盛米饭
  • 客人 (吃饭

需要的人员大大增加了, 每个人员负责的任务大大减少了。

多线程

根据职责分成下面几类线程 (每类线程的数量可能大于1)

  • 网络线程
  • 业务线程
  • 数据库操作线程

每种线程的职责大致如下。

  • 网络线程
    • 从网络中获取数据
    • 解析数据成我们需要的格式, 碰到无效数据则丢弃
  • 业务线程
    • 从数据库中取出玩家数据
    • 处理业务
    • 发送响应给客户端 (此处应该没有真的发送, 而是放入了网络数据的缓存里面)
  • 数据库操作线程
    • 定时保存数据到数据库
    • 处理好数据加锁以及缓存 (笔者假设的内容,并没有真的实现过)

需要的线程增加了, 每类线程负责的内容变少了。

总结

做饭复杂化有什么好处和代价呢?

代价

  • 这里先说一下代价
  • 需要的人变得很多了
    • 原本需要一个人,现在至少需要6个人
    • 会增加沟通的成本,管理费等。
    • 整个团队(客人除外) 很可能会受到木桶原理的限制
  • 当客人数量少的时候, 这套结构是复杂且浪费的。

好处

  • 好处就是可以更快的制作出饭菜,服务客人。
  • 当客人是2-3个的时候,一个人做饭还好
  • 当客人是4-8个的时候,一个人做饭就会很吃力
  • 当客人是30个的时候,一个人完全忙不过来, 很多客人会处于等待接应,极其愤怒的状态。
  • 但是切换成这套机制下, 30个人也还好,完全忙的过来。 并且,大多数情况下,客人会得到来自服务员的响应,少部分情况下才会出现无人搭理的情况。
  • 而且还可以根据情况进行人员数量的调整。
    • 如果做饭比较慢,则增加厨师的数量
    • 如果配菜比较慢,则增加打杂的数量
    • 等等。。。

多线程比起单线程有什么好处和代价呢?

代价

  • 同样, 还是先说一下代价
  • 编写起来比较复杂
  • 需要处理多线程数据同步, 以及锁的问题。
  • 可能会碰到更多的 更复杂的 bug 。

好处

  • 充分利用计算机多核优势
  • 可以同时处理更多的请求
  • 单线程情况下, 同时只能处理一个请求,多线程则同时能处理多个请求
  • 单线程情况下,在处理任务中的时候,后续请求会卡在网络层里等待。 多线程模型下,数据会从网络层拿出来, 封装成我们需要的数据格式, 并丢弃无效请求。
  • 理论上来说, 大部分应用程序的处理请求的并发,多线程的极限比单线程大的多得多。
  • 解耦
    • 单线程程序在编写的时候也可以解耦, 但是图方便可能很少些单线程的会那样做😂
  • 在 GUI 程序下, 单线程情况下, 如果碰到一个比较重的任务时(需要执行3-10s) ,UI 会卡住,在表现上是整个程序卡住了, 会给人非常不好的感觉。 把这个重的任务放到别的线程执行,则不会卡住 UI 线程, 用户会获取较好的体验✔️
  • 请求多, 增加网络线程的数量。 业务处理耗时比较久,增加业务处理的线程。 (注意: 线程调度切换也是需要代价的, 并不是越多的线程越好,但是适当的数量增加肯定是好的

那么,什么时候用呢?

笔者给出的建议是根据需求来决定。

比如, 做一个很小的程序的时候, 单线程开发比较快, 当然选择单线程了。

开发大型程序(网游服务端,对并发有要求) 肯定要使用多线程模型的。

拓展阅读

0%