前面介绍 Actor Model 时,Actor 是解决并发的关键原语。而 Grains 是 Orleans 编程的关键原语。
Grains 是构建 Orleans 应用程序的一部分,每个 Grains 是相互独立(隔离)、分布和持久性的原子单元。
每个 Grains 即独立,又互相调用。Orleans 将 Grain 作为程序的基本单元,将数据封装其中,每个 Grain 通过公开的方法接受数据、处理数据并将数据传给其它对象。因此,Grains 可以被当作一个小型的“机器”。
从今天开始我们陆续介绍 Grain 的用法 。
GrainReference
在前面基础示例中,客户端是通过如下代码进行调用 SayHello 。
var helloGrain = client.GetGrain<IHelloGrain>(1);
我们知道这是获取一个 IHelloGrain 实例化对象。然而,通过编译器进行调试时,发现 helloGrain 是一个代理对象,类型为: GrainReference,它在运行时,也实现了 IHelloGrain 接口,而且还封装了逻辑标识,该标识由目标 Grain 类型和主键组成。
在分布式系统 中,对象引用不能代表实例标识,因为引用通常仅限于单个地址空间。因此,grain 必须具有标识,无论它是否处于活动状态,以便我们可以按需激活它。而 GrainReference 就是代表目标 Grain 的逻辑标识,独立于 Grain 的物理位置,即使在系统完全重启后仍然有效。
所以, GrainReference 封装的 Grain 标识是用于调用目标 Grain 。而且,每个 GrainReference 都指向一个 Grain 实例,同时我们可以创建多个 GrainReference ,它们都指向同一个 Grain 实例。
Grain 标识由目标 Grain 类型和主键组成。主键由 Grain 的调用者来确定。主键可以是 GUID 、long 、string 、复合主键(GUID + string 或 string + long)。
GUID
在多个进程中请求一个 Grain 时,可能会造成资源无法协调分配,或者锁定的资源造成瓶颈,这时 GUID 就能派上用场。因为 GUID 的发生冲突的可能性很低,因此我们在构建 Orleans 系统时默认使用 GUID 。
GUID 在代码中的使用如下:
//首先定义接口时,要继承 Orleans 提供的接口,我们只要按照这个约定就行
public interface IExample : IGrainWithGuidKey
{
Task<Guid> GetKey();
}
public class Example : Grain, IExample
{
// Example 类方法里可以通过 this.GetPrimaryKey();获取主键
public Task<Guid> GetKey()
{
return Task.FromResult(this.GetPrimaryKey());
}
}
//外部客户端使用
var grain = clent.GetGrain<IExample>(Guid.NewGrid());
//内部客户端使用,IGrainFactory 来获取 grain
var exampleGrain = grainFactory.GetGrain<IExample>(Guid.NewGrid());
long
long 实用性比较高,特别是持久化到关系性数据库中,数字检索比较 GUID 或字符串效率高。
long 的用法如下:
public interface IExample : IGrainWithIntegerKey
{
Task<long> GetKey();
}
public class Example : Grain, IExample
{
public Task<long> GetKey()
{
return Task.FromResult(this.GetPrimaryKeyLong());
}
}
//外部客户端或内部客户端调用与 Guid 使用一样
string
string 的用法如下:
public interface IExample : IGrainWithStringKey
{
Task<string> GetKey();
}
public class Example : Grain, IExample
{
public Task<string> GetKey()
{
return Task.FromResult(this.GetPrimaryKeyString());
}
}
//外部客户端或内部客户端调用与 Guid 使用一样
复合主键
复合主键由 GUID 和 string 组合或 string 和 long 组合,只需 Grain 接口继承 IGrainWithGuidCompoundKey 或 IGrainWithIntegerCompoundKey 接口。
public interface IExample : IGrainWithGuidCompoundKey
{
Task<Guid> GetKey();
}
public class Example : Grain, IExample
{
public Task<Guid> GetKey()
{
string keyExt;
return Task.FromResult<this.GetPrimaryKey(out keyExt));
}
}
//外部客户端使用
var grain = clent.GetGrain<IExample>(Guid.NewGrid(),"string key");
//内部客户端使用,IGrainFactory 来获取 grain
var exampleGrain = grainFactory.GetGrain<IExample>(Guid.NewGrid(),"string key");
或
public interface IExample : IGrainWithIntegerCompoundKey
{
Task<long> GetKey();
}
public class Example : Grain, IExample
{
public long GetKey()
{
Task<string> keyExt;
return Task.FromResult(this.GetPrimaryLongKey(out keyExt));
}
}
//外部客户端使用
var grain = clent.GetGrain<IExample>(1,"string key");
//内部客户端使用,IGrainFactory 来获取 grain
var exampleGrain = grainFactory.GetGrain<IExample>(1,"string key");
今天先介绍到这。
最后,祝大家学习愉快!