农企新闻网

分手厨房多少钱(程序员玩)

发布者:高熙一
导读引言如果你还在想办法理解协程 是什么,那么就让我们玩一玩分手厨房~Overcooked,是一款多人烹饪游戏,玩家需要在特定的时间内做出尽可能多的菜。据说玩了的情侣会分手,所以又名



程序员玩《分手厨房》,是什么理解?

引言

如果你还在想办法理解协程 (coroutine)是什么,那么就让我们玩一玩分手厨房~

Overcooked,是一款多人烹饪游戏,玩家需要在特定的时间内做出尽可能多的菜。据说玩了的情侣会分手,所以又名分手厨房。你想不想要挑战一下(*^▽^*)

今天的主题是协程 (coroutine),与分手厨房有什么关系呢?协程 (coroutine),是现代编程里面少不了并且重要的概念。它不仅让你的代码逼格更高,也让你的程序在特定场景下性能更好!

很多人花了很多时间并不一定能理解它。而游戏,却很容易理解,所以本文借助分手厨房游戏来讲讲什么是协程。


Overcooked

先让我们来看看分手厨房的玩法——

程序员玩《分手厨房》,是什么理解?

如上图,我们一共有四个玩家,分别控制着带厨师帽的小人(没有厨师帽的是一些NPC)。

游戏开始后,左上角会不停地出现订单,而玩家们通过不停地完成这些订单得分。

程序员玩《分手厨房》,是什么理解?

每个订单都会标明需要什么材料,比如红色的代表西红柿,灰色的是蘑菇,等等。每个订单有自己的制作流程,比如先把西红柿切碎,然后拿去煮,接着盛到盘子里上菜。哒哒,明白这些规则就可以上手玩耍了~

做菜越快,完成的订单越多,积分也就越高。如何才能更快地更好地完成订单呢?需要小伙伴分工明确,密切地配合,马不停蹄地做菜。比如同学A负责切菜,拿食材,同学B负责煮,上菜等等。有时候能者还要干更多的活。

程序员玩《分手厨房》,是什么理解?

简单的规则,但是需要不简单的操作和配合。订单不停地出现,长时间不能完成的订单就会销毁,然后被扣分。长时间煮着的食物,如果不盛出来就会着火,着火就要去救火。两个人一不小心就容易发生冲突,该拿的食材没有拿,或者互相撞在一起o(╥﹏╥)o

但是这些不简单的操作,今天你都不用关心,就可以理解协程!



协程/Coroutine

协程可以让计算机程序在IO密集型的场景下,支持更多的请求,而且比多线程的方式,节省更多的资源,性能更优。

那什么是协程呢?维基百科的定义是——

协程(英语:coroutine)是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。

定义里面的关键词是协作式挂起恢复。是不是有点难理解?实际上它们就真真切切地存在分手厨房里面:

· 协作式,玩家们不停地协作制作订单~

· 挂起,当食材切好,放在锅里煮着的时候,这个订单就被“挂起”了~

· 当菜煮好的时候,你就去盛它,这个订单就被恢复了~

但是协程比分手厨房奇妙的地方在于,我们不用像游戏里的小人一样忙手忙脚,不知所措,只需要声明要制作的订单。计算机就会充当游戏里的小人帮我们把订单完成得漂漂亮亮。这些订单就是我们的代码,但是它们又不同于常见的代码。它们是借助于async, await构造的协程/coroutine,看起来像是同步的代码,但是计算机会用异步的方式执行。

什么是同步的代码,什么又是异步的方式呢?什么是异步的执行用同步的方式来编写代码?


异步的代码是什么?

首先什么叫同步和异步。同步是什么?

举个例子,我们看视频的时候,如果画面和声音不同步,会觉得很别扭。所以同步可以理解为多个对象具有相对应的关系。

异步我们生活中用得很少,它一般是在专业领域出现。比如异步IO,异步通信,英文是asynchronous。简单理解就是不是同步。(<--这不是废话嘛。)

类比分手厨房,订单的制作就是异步的方式——当出现一个订单的时候,我们有空的时候,就会去拿食材,然后切菜。但是如果其他菜已经做好了,我们就会放下当前的订单,去处理其他的订单。所以订单不是一开始制作,不停地烹饪,直到这个订单完成,才去制作其他订单,而是中间穿插了其他订单的制作。这就是异步方式地烹饪菜肴。

为了加深理解,让我们一起再看个例子——一周的工作


上了一周的班

比如我们有个函数AWeek,它要做的事情是打印周一,播放音乐,打印周二,刷个朋友圈,打印周三。

同步的代码的样子:

function AWeek() {
  // 同步的代码,同步的方式
  print('Monday')
  play_music() // block call
  print('Tuesday')
  browse_moment() // block call
  print('Wednesday')
}


程序员玩《分手厨房》,是什么理解?

play_music()browse_moment()是阻塞调用。程序会等着这些事完成,然后继续执行接下来的步骤。

如果它们是非阻塞调用,那么异步代码长什么样子呢?以Javascript 为例子,在没有async,await的久远年代,它们写得像下面这个样子——

function AWeek() {
  print("Monday")
  Playing_Music(
    () => {
        print('Tuesday');
        ((cb) => {
            Browsing_Moment(cb);
        })(() => { print("Wednesday") });
    }
 ) 
}

可以看到,代码由各种callback串起来,晦涩难懂,维护起来也困难(对于大神除外)。ES6有了Promise,代码可以写成下面的方式

function AWeek() {
  print("Monday")
  Playing_Music_Promise().then(() => {
    print('Tuesday');
    Browsing_Moment_Promise().then(() => {
        print('Wednesday');
    })
 })
}

接着ES7有了async, await,代码就可以很方便写成

async function AWeek() {
  // 异步的代码,同步的方式编写
  print('Monday')
  await Playing_Music_Promise();
  print('Tuesday')
  await Browsing_Moment_Promise();
  print('Wednesday');
}

跟同步的代码长得几乎一模一样,容易理解和编写!没有所谓的callback一个串一个。它们长得虽然相似,但是执行起来确实异步的,因为它们是协程。

执行时候,像下图那样执行,中间加入许多方框,做了好多事情。

程序员玩《分手厨房》,是什么理解?

所以异步的代码做事情仍按照顺序,但是并不是时间上相连的顺序,而是逻辑上的顺序。带有async, await, yield, promise的函数就是协程/coroutine,也就是异步的代码。


再议协程/Coroutine

现在,经过了分手厨房和一周的工作(AWeek),我们可以用更通俗易懂地方式来理解coroutine——

协程/Coroutine就是函数,只不过是可以suspend和resume的函数,也就是可以暂停这个函数的执行 (在suspend的地方直接返回到caller),去做其他事情,然后在恰当的时候恢复到你离开的位置继续开始运行。

让我们代入线程后看看是怎么实现的,下图左边灰色的coroutine(一个特别点的函数)。当它被调用的时候,被切成了两部分,蓝色框框和黄色框框:线程1在执行完成蓝色的框框后,就继续做其他事情了;第二部分黄色的框框被suspend了。当时机出现的时候,线程2(可以是线程1)就开始执行第二部分黄色的框框。

程序员玩《分手厨房》,是什么理解?


Coroutine in C++ 20

MicroStrategy Intelligence Server使用C++打造, 而C++ 20加入了协程/coroutine的支持。所以借助协程/coroutine,可以让我们强大的intelligence Server性能再上一个台阶,以及更容易编写和维护庞大的代码!


附注

特别鸣谢同事Roger带我玩分手厨房。


参考文档

https://store.steampowered.com/app/448510/Overcooked/?l=schinese&curator_clanid=28673811

https://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B

https://zhuanlan.zhihu.com/p/237952115

https://zhuanlan.zhihu.com/p/237067072


关注了解更多微策略最新动态,行业资讯以及程序员日常