Orleans解决并发之痛(一):单线程
程序在运行过程中有时会莫名其妙出现代码的某些约束或者执行结果和理想状况不一样,正常逻辑怎么会出现这样的情况?到底发生了什么?好像见了鬼!瞬间好无助。
谁来救救我
大多数出现正常逻辑很难解释的时候,我们可能会想到并发问题,因为好像只有并发才会能说服自己。为了验证和解决这个问题,我们可能会尝试一些方案,在并发的情况下我相信很多人都使用过锁,锁确实也能帮忙我们解决问题,不然它干嘛存在。
但随着业务逻辑的持续复杂,锁的使用可能无处不在。首先大家都知道锁本身的机制很耗性能;然后锁本身不涉及什么编程模式,所以在业务代码中融入大量锁对代码本身的稳定性也有一定影响。
经过查找资料,因为本身的项目是基于.NET,所以发现Microsoft Orleans好像可以比较好的满足解决并发的需求。
Orleans之前,先来扯一扯Actor模型
Actor是以单线程存在的,所有消息都是顺序到达的,每次收到消息后,就放入队列,而它每次也从队列中取出消息体来处理;
每一个Actor有一个Id和它对应,一个Id对应的Actor只会在集群中存在一个,使用者只需要通过Id就能随时访问不需要关注该Actor在集群的什么位置;
每一个Actor看作是一个独立的实体,拥有自己独立的状态。Actor与Actor之间可以进行消息通知;
注:有状态的 Actor在集群中一个Id只会存在一个实例,无状态的可配置为根据流量存在多个,无状态的情况看具体业务需求。
Actor System
再来扯一扯Orleans框架
Orleans 提供了一个简单的方法来构建大规模、高并发、分布式应用程序,被认为是Actor模型的分布式版本,是一种改进的Actor模型。在Orleans中,Actors被称作Grains,采用接口来表示,Actors的消息用异步方法来接收,方法返回值必须是Task or Task<T>。
Orleans几个核心角色:
Grains(Actors)
Grains是Orleans应用程序的业务逻辑实现与抽象,Grains是彼此孤立的原子单位,分布的,持久的。 一个典型的Grain是有状态和行为的一个单实例。
Silo
Silo是一个主机服务,里面主要用于执行Grains,也就是说Grains开发完成后需要注册到Silo中,然后等待调用。它监听一个端口,用来监听从Silo到Silo的消息或者从客户端到Silo的消息的,典型的Silo就是,每台机器运行一个Silo,会对外暴露网关地址供调用。
Cluster(集群搭建的时候会具体介绍)
大量的Silo同时在一起工作就形成了Orleans的集群,Orleans运行完全自动化的集群管理。
Client
具体的应用客户端,可以是控制台、Web应用程序、WPF等一切.NET端技术。
开始接触Orleans Sample的时候,第一感觉项目结构和gRPC还挺像的,如果你之前有接触,一定感觉很亲切:
定义一个接口(Interfaces)
实现接口(Grains) -- 添加引用Interfaces
启动服务端(Silo)-- 添加引用Interfaces,Grains
启动客户端 (Client)-- 添加引用Interfaces
练习过程中对Nuget安装Orleans相关依赖包可能会有一些模糊,这里说明一下我的具体步骤,希望尽快帮忙实现效果,所有程序集使用.Net Framework的版本都是4.6:
程序集名称 | 类型 |
Nuget依赖包 Microsoft.Orleans. |
引用 |
---|---|---|---|
Interfaces | 类库 | Core | - |
Grains | 类库 | Core | Interfaces |
Silo | 控制台程序 |
Core OrleansCodeGenerator OrleansProviders OrleansRuntime |
Interfaces Grains |
Client | 控制台程序 |
Core OrleansCodeGenerator |
Interfaces |
在Silo项目中添加配置文件 OrleansConfiguration.xml:
<?xml version="1.0" encoding="utf-8" ?>
<OrleansConfiguration xmlns="urn:orleans"><Globals><SeedNode Address="localhost" Port="11111" /></Globals><Defaults><Networking Address="localhost" Port="11111" /><ProxyingGateway Address="localhost" Port="30000" /></Defaults>
</OrleansConfiguration>
SeedNode:集群中主Silo地址,生产环境下不要这么使用。以这种方式配置主Silo的情况下,其他Silo加入集群需要等主Silo先启动。之后会介绍SystemStore来维护集群成员关系;
Networking:内部Silo与Silo之间通信地址;
ProxyingGateway:客户端调用的网关地址;
在Client项目中添加配置文件 ClientConfiguration.xml:
<?xml version="1.0" encoding="utf-8" ?>
<ClientConfiguration xmlns="urn:orleans"><Gateway Address="localhost" Port="30000"/>
</ClientConfiguration>
Gateway:配置Silo对外的网关地址;
集群下可以配置多个Gateway节点,如下:
<Gateway Address="gateway1" Port="30000"/>
<Gateway Address="gateway2" Port="30000"/>
注意:配置文件需要设置属性 "复制到输出目录"
configuration
Grain说明:
每个Grain都是单实例的,具有唯一标识。根据唯一标识获取Grain,这个标识可以是GUID、String、Long、混合类型。
在Grain内如果发送消息给其他Grain,需要使用 this.GrainFactory.GetGrain,不能通过 GrainClient.GrainFactory.GetGrain。
var test = GrainClient.GrainFactory.GetGrain<ITest>(0); // long类型的primaryKey 0
public class TestGrain : Orleans.Grain, ITest
{private int num = 0;public Task AddCount(){num++;Console.WriteLine(num);return Task.CompletedTask;}
}
Client说明:
同时启动3个Task,每个Task内并行200次调用AddCount方法。如果没有做特殊的处理,num的结果肯定是乱的,并不会出现一直累加的效果。
private static void DoClientWork()
{var t1 = Task.Factory.StartNew(() =>{AddCount();});var t2 = Task.Factory.StartNew(() =>{AddCount();});var t3 = Task.Factory.StartNew(() =>{AddCount();});Task.WaitAll(t1, t2, t3);
}static void AddCount()
{var test = GrainClient.GrainFactory.GetGrain<ITest>(0);Parallel.For(0, 200, (i) =>{test.AddCount();});
}
实际上执行最终的结果是600,并不会出现不一致的变化效果,这足以说明同一个Grain内部是单线程执行。
Test Result
相关文章:
.NET的Actor模型:Orleans
微软分布式云计算框架Orleans(1):Hello World
微软分布式云计算框架Orleans(2):容灾与集群(1)
Aaron Stannard谈Akka.NET 1.1
使用Akka.net开发第一个分布式应用
Orleans入门例子
Orleans例子再进一步
Orleans稍微复杂的例子—互动
Orleans简单配置
Orleans配置---持久化
Orleans—一些概念
Orleans的集群构建
Oleans集群之Consul再解释
原文地址:http://www.jianshu.com/p/141ea382d242
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
Orleans解决并发之痛(一):单线程相关推荐
- Orleans解决并发之痛(五):Web API
通过前面几篇文章的介绍,可能会疑问怎么在实际开发中调用Grain,之前Demo的Client都是基于控制台应用程序,实际开发下可能是基于Web Form.Web API.MVC......,由于一时短 ...
- Orleans解决并发之痛(四):Streams
Orleans 提供了 Stream扩展编程模型.此模型提供了一套API,使处理流更简单和更健壮.Stream默认提供了两种Provider,不同的流类型可能使用不同的Provider来处理,Simp ...
- Orleans解决并发之痛(三):集群
Orleans本身的设计是一个分布式的框架,多个Silo构成集群,Grains分布在多个Silo中.一旦一个Silo挂了,原来归属这个Silo的Grains会自动在其他Silo中激活.生产环境下还是需 ...
- Orleans解决并发之痛(二):Grain状态
Grains是Orleans应用程序的构建块,它们是彼此孤立的原子单位,分布的,持久的, 一个典型的Grain是有状态和行为的一个单实例,每个Grain实例的在单线程内执行,Grain之间共享数据通过 ...
- 开发之痛:稳定的测试环境,怎么就那么难
简介:开发之痛:稳定的测试环境,怎么就那么难.对于生产环境,准确.稳定最重要,我们推荐以应用为中心的基于OAM和IaC的实践方式:对于测试环境,隔离.低成本和稳定的依赖是最重要的,我们推荐基于稳定环境 ...
- 解决Intel12代酷睿CPU单线程调度问题(二)
文章目录 (一)前情回顾 1.1 十二代酷睿大小核和电源模式 1.2 单线程程序问题 (二)设置优先级(priority) (三)设置相关性(affinity) (四)解决 (一)前情回顾 1.1 十 ...
- 神了,一次解决Java所有痛难点!
今天下班的时候,走在路上,听到前面几个美女在吐槽: "我们公司的程序员 7 点就下班了,工资肯定不高" "程序员还能 7 点就下班啊?真是刷新了我的认知" 不知 ...
- 值得安利!8款windows神级软件,真解决了不少痛点啊!
推荐8款电脑端非常实用的神仙软件,可以解决很多问题,喜欢的话记得点赞支持哦~ 1.火绒安全软件 火绒安全软件绝对要吹爆!火绒安全软件是一款享誉盛名的脑防御及杀毒类安全软件,它轻巧.高效.免费.好用,可 ...
- 【Java并发编程】并发之痛 Thread,Goroutine,Actor
本文基于我在2月27日Gopher北京聚会演讲整理而成,进行了一些补充以及调整.投稿给<高可用架构>公众号首发. 聊这个话题之前,先梳理下两个概念,几乎所有讲并发的文章都要先讲这两个概念: ...
最新文章
- java查询结果自定义显示_JPA自定义对象接收查询结果集操作
- pix2pixHD笔记
- 《公安机关互联网安全监督检查规定》今日起实施,要检查你家的数据中心了...
- java反射异常之java.lang.NoSuchFieldException: school
- 【dfs】【bfs】【链表】 求连通分量 (ssl 1759)
- Spark GraphX相关使用方法
- 微型计算机机房湿度不宜过大,全国计算机一级考试选择题试题与详细答案(免费)...
- 软件测试全套教程,软件测试自学线路图
- Ps调色磨皮降噪抠图胶片特效模拟常用100款滤镜合集一键安装支持PSCC2015-2019win64
- php 数组添加键值对,php 给数组增加键值对
- 学生成绩管理系统html代码,学生成绩管理系统(含源代码)30.doc
- solidworks2014可否保存成以前版本?--问题解决
- 正版软件 |Windows 10 家庭版操作系统软件 终身授权
- Unity给模型添加逼真效果材质
- Lemp + Wordpress 快速搭建个人博客
- R语言使用lm函数构建多元回归模型(Multiple Linear Regression)、并根据模型系数写出回归方程、使用resid函数或者residuals计算出模型的残差值
- 测试ocx(MFC ActiveX控件)
- java 字节单位换算_【java虚拟机】内存使用单位换算
- 经常玩电脑正确的坐姿_细说用电脑的正确坐姿
- Confluence 6 新 Confluence 安装配置一个数据源连接
热门文章
- python引入模块时import与from ... import的区别
- 思科路由PPPOE基本配置
- 4.WCF事务【Transaction】
- iNeuOS工业互联网操作系统,顺利从NetCore3.1升级到Net6的过程汇报,发布3.7版本...
- 国产知名老牌 PDF 工具正式开源
- 如何通过 C# 自动捕获一个文件的变更?
- .NET 6 数组拷贝性能对比
- ABP Framework 研习社经验总结(6.28-7.2)
- 应对「高并发」的思路
- 乐观锁与悲观锁各自适用场景是什么?