1. 程式人生 > >Orleans 2.0官方文件(閆輝的個人翻譯)——4.1 開發一個Grain

Orleans 2.0官方文件(閆輝的個人翻譯)——4.1 開發一個Grain

設定

在編寫實現grain類的程式碼之前,請新建一個面向.NET Standard(首選)或.NET Framework 4.6.1或更高版本的類庫專案(如果由於依賴性而無法使用.NET Standard)。grain介面和grain類可以在同一個類庫專案中定義,也可以在兩個不同的專案中定義,以便更好地分離介面和實現。無論哪種情況,專案都需要引用Microsoft.Orleans.Core.AbstractionsMicrosoft.Orleans.CodeGenerator.MSBuildNuGet包。

有關更詳細的說明,請參閱Tutorial One - Orleans Basics

Project Setup部分。

grain介面和類

grain之間彼此互動,它能被外部呼叫其方法,這些方法是grain介面宣告中的一部分。grain類實現一個或多個先前宣告的grain介面。grain介面的所有方法都必須返回一個 Task(對於void方法),一個 Task<T>或一個 ValueTask<T>(對於返回型別值的型別為T的方法)。

以下是Orleans 1.5版的Presence Service示例的摘錄:

//an example of a Grain Interface
public interface
IPlayerGrain : IGrainWithGuidKey { Task<IGameGrain> GetCurrentGame(); Task JoinGame(IGameGrain game); Task LeaveGame(IGameGrain game); } //an example of a Grain class implementing a Grain Interface public class PlayerGrain : Grain, IPlayerGrain { private IGameGrain currentGame; // Game the player is currently in. May be null.
public Task<IGameGrain> GetCurrentGame() { return Task.FromResult(currentGame); } // Game grain calls this method to notify that the player has joined the game. public Task JoinGame(IGameGrain game) { currentGame = game; Console.WriteLine( "Player {0} joined game {1}", this.GetPrimaryKey(), game.GetPrimaryKey()); return Task.CompletedTask; } // Game grain calls this method to notify that the player has left the game. public Task LeaveGame(IGameGrain game) { currentGame = null; Console.WriteLine( "Player {0} left game {1}", this.GetPrimaryKey(), game.GetPrimaryKey()); return Task.CompletedTask; } }

grain方法的返回值

返回值的型別為T的grain方法,在grain介面中定義為返回一個 Task<T>。對於未標記async關鍵字的grain的方法,當返回值可用時,通常通過以下語句返回:

public Task<SomeType> GrainMethod1()
{
    ...
    return Task.FromResult(<variable or constant with result>);
}

一個不返回值的grain方法,實際上是一個void方法,在grain介面中定義為返回一個Task。返回Task表示非同步執行和方法的完成。對於未標記async關鍵字的grain方法,當“void”方法完成其執行時,需要返回以下特殊值Task.CompletedTask

public Task GrainMethod2()
{
    ...
    return Task.CompletedTask;
}

標記為async的grain的方法,直接返回值:

public async Task<SomeType> GrainMethod3()
{
    ...
    return <variable or constant with result>;
}

一個“void”的grain的方法,若被標記為async,則不返回任何值,只是在執行結束時返回:

public async Task GrainMethod4()
{
    ...
    return;
}

如果一個grain方法,接收從另一個非同步方法呼叫的返回值,無論此非同步呼叫是或不是grain的方法,都不需要對該呼叫執行錯誤處理,它只需簡單地將從該非同步呼叫接收的Task,作為其返回值:

public Task<SomeType> GrainMethod5()
{
    ...
    Task<SomeType> task = CallToAnotherGrain();
    return task;
}

類似地,一個“void”的grain的方法,可以返回另一個呼叫返回給它的Task,而不是await它。

public Task GrainMethod6()
{
    ...
    Task task = CallToAsyncAPI();
    return task;
}

ValueTask<T> 可以用來代替 Task<T>。

grain引用

一個grain引用是一個代理物件,它實現了與對應的grain類相同的grain介面。它封裝了目標grain的邏輯標識(型別和唯一鍵)。使用grain引用,來呼叫目標grain。每個grain引用只能用於單個grain(grain類的單個例項),但是可以為同一grain建立多個獨立的引用。

由於grain引用表示目標grain的邏輯標識,因此它與grain的物理位置無關,即使在系統徹底重新啟動後,也保持有效。開發人員可以像任何其他.NET物件一樣使用grain引用。它可以傳遞給一個方法,用作方法的返回值等,甚至可以儲存到持久化的儲存中。

可以通過將grain的標識,傳遞給GrainFactory.GetGrain<T>(key)方法,來獲得grain引用,其中,T是grain的介面,而key是該型別中grain的唯一鍵。

以下演示瞭如何獲得上文中定義的IPlayerGrain介面的grain引用。

從grain類的內部:

    //construct the grain reference of a specific player
    IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);

從Orleans的client:

    IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);

grain的方法呼叫

Orleans程式設計模型基於非同步程式設計

使用前一個示例中的grain引用,以下是如何執行grain的方法呼叫:

//Invoking a grain method asynchronously
Task joinGameTask = player.JoinGame(this);
//The await keyword effectively makes the remainder of the method execute asynchronously at a later point (upon completion of the Task being awaited) without blocking the thread.
await joinGameTask;
//The next line will execute later, after joinGameTask is completed.
players.Add(playerId);

可以join兩個或更多個Tasks;join操作建立一個Task,在其所有組成任務都完成之後,該Task完成。當一個grain需要啟動多個計算,並等待這些計算完成才能繼續時,這種模式很有用。例如,生成網頁(由多個部分組成)的前端grain,可能會產生多個後端呼叫,一個部分一個呼叫,併為每個結果接收一個Task。然後,grain將await這些Tasks的join; 當join的Task完成後,則各個Task已經完成,且已經收到格式化網頁所需的所有資料。

例:

List<Task> tasks = new List<Task>();
Message notification = CreateNewMessage(text);

foreach (ISubscriber subscriber in subscribers)
{
   tasks.Add(subscriber.Notify(notification));
}

// WhenAll joins a collection of tasks, and returns a joined Task that will be resolved when all of the individual notification Tasks are resolved.
Task joinedTask = Task.WhenAll(tasks);
await joinedTask;

// Execution of the rest of the method will continue asynchronously after joinedTask is resolve.

虛方法

grain類可以選擇性地重寫OnActivateAsync和OnDeactivateAsync虛方法,這些方法在類的每個grain啟用和停用時,由Orleans執行時呼叫。這使grain程式碼有機會執行額外的初始化和清理操作。若OnActivateAsync丟擲異常,則啟用失敗。雖然OnActivateAsync(如果被重寫)總是作為grain啟用過程的一部分被呼叫,但OnDeactivateAsync不保證在所有情況下都被呼叫,例如,在伺服器故障或其他異常事件的情況下。因此,應用程式不應依賴於OnDeactivateAsync執行關鍵操作,例如狀態更改的持久化。應用程式應只用它於力所能及的操作。