Orleans入門例子
這是Orleans系列文章中的一篇.首篇文章在此
一.鋪墊。
雖然是個入門例子,還是需要一些鋪墊。
Orleans的最小完全體,應該分為2個部分。一個是Orleans客戶端,一個是Orleans服務端,這里為什么要加上“Orleans”這個限定詞語呢?那是因為Orleans的完全體,才是普通意義上的服務端主程。它們共同構成了游戲服務器,網站服務器等等。
在Orleans客戶端中,我們使用GrainClient類以及Grain類,在Orleans服務端內,我們主要使用silo類和grain類。這里要說說Silo類,前面說過Grain類是處於“單線程機制”約束下的類,那么它們運行在哪個地方呢?就是Silo類所在的地方。Silo類是Grain地代碼實際執行的地方,它是Grain類的宿主,它承載着所有的Grain實例,也許是幾百萬個Grain實例。在一些語境下,silo,silohost,以及Orleans服務端,這三個詞語有可能代表同一個意思.
一個外部請求的處理大部分情況下需要很多個Grain實例,進行一連串的方法調用后才能處理完畢,這些Grain實例形成一個處理消息的鏈條,這個消息流走於Grain鏈內直至處理完畢。那么這個消息是如何第一次到達Grain鏈條里呢?GrainClient類的作用就是入口,它通知Silo類,有新消息達到,它需要哪個Grain類實例,需要調用特定的方法等。
經過以上鋪墊,要想創造一個Orleans完全體,我來用vs2017創建一個解決方案,里面添加4個項目:Client,Host,Grains,IGrains。它們的作用分別解釋如下:
- Client:這個顯而易見,里面就是要運行GrainClient的。它要和Host通信,這就要求它引用IGrains項目。這是個控制台項目
- Host:這個也是顯而易見,里面就是要運行Silo的。它應該引用Grains項目以及IGrains項目,因為它要承載Grain(這就要求引用Grains類),並且需要Grain實例間的通信(這就要求引用IGrains項目),這是個控制台項目
- Grains:這個里面實現所有IGrain載明的接口,實現所有的Grain類,包括它們的方法以及字段。(它要求引用IGrain。。。廢話)這是個類庫項目
- IGrains:這里放置所有Grains類要擴展的接口。這是個類庫項目。
同時為了使用Orleans框架,我們還需要引用Orleans的類庫,官方教程里有方案,不過,我們采用簡單的辦法,統一引用一個類庫集合,下文有述。
好吧,以上解釋不管懂與不懂,你就暫且記下,先按照步驟一步一步來吧。也許某個階段,你就突然懂了。我相信在讀的各位對這種醍醐灌頂的感覺一定不陌生。
按照以上套路,我開始了我的工作,我打算跟世界say Hi:
二.創建
我創建了四個項目的解決方案,它長成這個樣子,注意它們的.net框架版本都是4.6.1:
好了我們要引用Orleans類庫啦,說了半天,終於要主角登場啦,好激動,所以我nuget引用了Microsoft.Orleans.Server,它長這樣子:
里面沒有實際內容,我現在先弄IGrains,它很簡單,就一個接口一個方法:長成這樣:
我再弄Grains項目:它就是要實現IGrains項目里的接口,所以先引用哪個項目,然后實現它,長這樣子。
我再實現Client項目,它需要引用IGrains項目,它長這樣子:
最后是Host類,它長這樣子:
現在我高興的運行這個Orleans完全體,它再一連串的日志記錄之后,跳出了 hello world如下圖
…我成功地創造了Orleans地完全體。好了全系列文章到此結束。
再見
補充
噢,我還需要補充一下下。
搞了半天,鬧這么大動靜,就寫了個簡版的WCF?並不是,這里只是展示了碼Orleans的主要步驟。這里有幾個要點需要解釋一下:
1.IGrains的所有接口方法,必須是返回Task類的。這個是必須的,因為Orleans的“單線程機制”,是建立在Task類之上的。它是利用TaskScheduler類,實現“單線程機制”的。啥?有人問怎么實現的?你確信自己入門教程還沒有看完就想知道?…以后再說吧。反正接口的方法,必須是返回Task。 |
2.IGrains接口擴展自IGrainWithInteger接口,這個IGrainWithInteger接口是Orleans提供的,之前說過,Grain實例之間需要通信,這就需要彼此區分,要有各自的主標識。這個接口,就規定了主標識是長整數(名字是整數,但是實際上是長整數)。Grain實例的主標識還可以是其他類型:比如字符串和Guid等等。 |
3.Grains項目中,實現了我規定的接口,就表明自己的主標識是長整數,它又擴展自Grain類,就表明自己受“單線程機制”約束了 |
4.Host項目,只是引用了Grains項目,但是沒有再代碼中具體使用。它如何知道自己要承載哪些Grain類?Host利用反射檢查所有目錄里的類庫文件,如果找到grain類,它就加載,並管理起來 |
5.GrainClient有靜態的,有動態的類,我這里先使用靜態類講解。動態類其實一樣。我調用的時候,使用一個參數“12345”。就是要告訴Host。我要激活主標識是12345的Grain類實例。然后又調用了它的say方法。它聰明的再host的控制台窗口打印出say hello。 |
到現在,我們就明白了,再Orleans的世界里,給grain發送消息,實質上是調用對應的接口,grain實例接收到消息以后,使用對應的方法進行處理。(吃瓜群眾:這不就是一個RPC框架嘛…呵呵。)
在這個簡單的例子里,展現出的東西還有很多,不過今天很晚了,打完收工。明天繼續說說這個例子展現的內容。