EventNext.net core下的一个事件驱动的应用框架,通过它代理创建的接口行为都是通过事件驱动的模式进行调用.由于EventNext的所有调用都是基于事件队列来进行,所以在资源控制上非常方便;它可以进行多样性的线程分配,其中Actor应用就是它的一种基础实现;在新的版中EventNext增加了一个新的特性就是线程容器,通过线程容器可以让N个类的行为在指定线程资源下运行。接来详细分析这个功能的应用。

线程容器的便利性

平时在多线程应用的时候一般都用线程池或自己定义线程处理,但这些都需要手动去处理和调用。实际有些情况是希望不同实例的所有方法运行在指定线程资源下,但又不想入侵式修改代码,这样处理起来就比较复杂了。但EventNext新版本的线程容器就能解决这种事情,它可以创建一个线程容器并指定那些对象的所有方法都在这个容器里执行,而容器的线程则可以根据实际情况来指定,这种完全透明的线程控制使用起来就非常方便(不过这版本的Actor暂不支持在线程容器中创建)。

接口定义准则

EventNext的所有任务都在由队列接管,但它实现的队列和平常的队列有所不同;EventNext的事件驱动队要求所有任务都用异步描述,它的特点是由上一个任务的完成来驱动下一下任务,不像同步处理队列在处理异步的时候不得不做线程等待。为了达到异步任务的要求接口的所有方法必须定义Task作为返回值(暂不支持属性处理)。

创建线程容器

组件提供一个EventNext.GetThreadContainer方法来获取一个线程容器,方法有两个参数,一个是容器的名称和对应容器的线程数量;当容器被创建后内部的线程数量不变,具体代码如下:

 var tc = EventCenter.GetThreadContainer("t1");

以上是获取一个名称为t1的线程容器,在不指定线程数的情况下为一个线程处理。接下来就可以通过容器创建相应的接口实例:

 var account = tc.Create<IAccount>();

以上是创建一个IAccount的实例,这个实例不管在多少个线程下调用最终都由t1这个线程容器去执行处理;每个容器可以创建多个接实例。

IAcouunt的实现

    [Service(typeof(IAccount))]
public class AccountImpl : IAccount
{ static AccountImpl()
{
Redis.Default.Host.AddWriteHost("192.168.2.19");
} public async Task Income(string name, int value)
{
await Redis.Default.Incrby(name, value);
} public async Task<string> Value(string name)
{
return await Redis.Default.Get<string>(name);
}
}

以上是针对一个Redis操作的实现,主要存在IO操作更容易测试到容器在不同线程下的差异。

测试代码

为了测试容器的效果,使用了不同的方式进行测试,分别是:不用线程容器和使用不同线程数的容器,测试代码如下:

  • 非线程容器

        static async Task None(int count)
{
var account = EventCenter.Create<IAccount>();
List<Task> tasks = new List<Task>();
var now = BeetleX.TimeWatch.GetElapsedMilliseconds();
for(int i=;i<;i++)
{
var t = Task.Run( async ()=> {
for (int k = ; k < count; k++)
await account.Income("ken",k);
});
tasks.Add(t);
}
await Task.WhenAll(tasks);
var value = await account.Value("ken");
Console.WriteLine($"none use time:{BeetleX.TimeWatch.GetElapsedMilliseconds()-now} ms");
}
  • 线程容器

        static async Task Threads(int threads, int count)
{
var tc = EventCenter.GetThreadContainer($"t{threads}",threads);
var account = tc.Create<IAccount>();
List<Task> tasks = new List<Task>();
var now = BeetleX.TimeWatch.GetElapsedMilliseconds();
for (int i = ; i < ; i++)
{
var t = Task.Run(async () => {
for (int k = ; k < count; k++)
await account.Income("ken", k);
});
tasks.Add(t);
}
await Task.WhenAll(tasks);
var value = await account.Value("ken");
Console.WriteLine($"{threads} thread use time:{BeetleX.TimeWatch.GetElapsedMilliseconds() - now} ms");
}

运行代码

        static async void Test()
{
Console.WriteLine("Warm-Up...");
await None();
await Threads(, );
await Threads(, );
await Threads(, );
for (int i = ; i < ; i++)
{
Console.WriteLine("Test...");
await None();
await Threads(, );
await Threads(, );
await Threads(, );
}
}

测试结果

Test...
none use time:1231 ms
1 thread use time:3479 ms
2 thread use time:2025 ms
4 thread use time:1208 ms
Test...
none use time:1246 ms
1 thread use time:3358 ms
2 thread use time:2025 ms
4 thread use time:1179 ms
Test...
none use time:1344 ms
1 thread use time:3385 ms
2 thread use time:1954 ms
4 thread use time:1187 ms
Test...
none use time:1210 ms
1 thread use time:3338 ms
2 thread use time:1933 ms
4 thread use time:1181 ms

默认情况下组件会针对请调用进行一个线程分配,这个分配机制依据队列的负载情况进行分配调用;线程容器则会根据当前容器的线程数来进行一个平均分配处理,从测试结果可以看到不同线程数下完成所需要的时间。

示例代码

https://github.com/IKende/BeetleX-Samples

事件驱动框架EventNext之线程容器的更多相关文章

  1. 【Java 并发】Executor框架机制与线程池配置使用

    [Java 并发]Executor框架机制与线程池配置使用 一,Executor框架Executor框架便是Java 5中引入的,其内部使用了线程池机制,在java.util.cocurrent 包下 ...

  2. 【Nginx】事件驱动框架和异步处理

    Nginx对请求的处理是通过事件触发的,模块作为事件消费者,仅仅能被事件收集.分发器调用.这与传统的Webserver是不同的. 传统的Webserver下,一个请求由一个进程消费.请求在建立连接后将 ...

  3. 从yii2框架中的di容器源码中了解反射的作用

    反射简介 参考官方简介的话,PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 此外,反射 API 提供了方法来取出函数.类和方法中的文档注释. YII2框架中 ...

  4. YII框架的依赖注入容器

    依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象. 所谓的依赖就是,一个对象,要使用另外一个对象才能完成某些功能.那么这个对象就 ...

  5. 【Redis】事件驱动框架源码分析

    aeEventLoop初始化 在server.c文件的initServer函数中,对aeEventLoop进行了初始化: 调用aeCreateEventLoop函数创建aeEventLoop结构体,对 ...

  6. 【Redis】事件驱动框架源码分析(单线程)

    aeEventLoop初始化 在server.c文件的initServer函数中,对aeEventLoop进行了初始化: 调用aeCreateEventLoop函数创建aeEventLoop结构体,对 ...

  7. 服务框架HSF分析之一容器启动

    大家平时都在用这个服务框架.简单阅读了下代码,了解其原理可以方便解决一些常见hsf的问题.限于篇幅,整个分析将分几个系列发布.第一篇将简单介绍Hsf的启动和各组件之间关系. 一.  Hsf总体架构 这 ...

  8. [ASP.NET Core 3框架揭秘] 异步线程无法使用IServiceProvider?

    标题反映的是上周五一个同事咨询我的问题,我觉得这是一个很好的问题.这个问题有助于我们深入理解依赖注入框架在ASP.NET Core中的应用,以及服务实例的生命周期. 一.问题重现 我们通过一个简单的实 ...

  9. Minor【 PHP框架】4.服务容器与服务提供者

    框架Github地址:github.com/Orlion/Minor (如果觉得还不错给个star哦(^-^)V) 框架作者: Orlion 知乎:https://www.zhihu.com/peop ...

随机推荐

  1. UVa 10323 【数学】

    UVa 10323 题目:计算阶乘在10000~6227020800之间的值,不在范围对应输出Under或者Over. 分析:简单题.数论.因为13!=6227020800,7!<10000&l ...

  2. day15 web前端之css

    css的概念以及初体验 概念: CSS(cascading style sheet)也就是层叠样式表:它是一种网页设计的新技术,现在已经被大多数浏览器所支持,层位网页设计必不可少的工具之一.优点:   ...

  3. SharpDX初学者教程第1部分:在Visual Studio 2013中设置SharpDX项目

    原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-1-setting-up-a-sharpdx-project-in-visual-studi ...

  4. 算法导论笔记:18B树

    磁盘作为辅存,它的容量要比内存大得多,但是速度也要慢许多,下面就是磁盘的的结构图: 磁盘驱动器由一个或多个盘片组成,它们以固定的速度绕着主轴旋转,数据存储于盘片的表面,磁盘驱动器通过磁臂末尾的磁头来读 ...

  5. Hbase架构与实现

  6. php parse_url linux 解析问题

    耕毅 解析url函数parse_url() (PHP 4, PHP 5, PHP 7) parse_url — 解析 URL,返回其组成部分 mixed parse_url ( string $url ...

  7. fakeroot与sudo的区别

    fakeroot 可以用来模拟 root 权限,以便建立特定权限与档案拥有者的压缩文件案(tar, ar, .deb 等).透过 LD_PRELOAD 的 dynamic loader 功能,用户不必 ...

  8. 你以为SSL是安全的吗?

    在现代的IT安全领域,很大程度上依赖SSL来保障通讯安全.但SSL是安全的吗? 在2005年,王小云证明SHA-1能在较短的时间内找到碰撞.王小云发现SHA-1的安全弱点是偶然还是必然? 就我所知,各 ...

  9. java反斜杠替换

    java replaceAll() 方法要用 4 个反斜杠,表示一个反斜杠 例如 str1="aa\bbb"; str2="aa'bbb"; 要想替换成 str ...

  10. UPC个人训练赛第十五场(AtCoder Grand Contest 031)

    传送门: [1]:AtCoder [2]:UPC比赛场 [3]:UPC补题场 参考资料 [1]:https://www.cnblogs.com/QLU-ACM/p/11191644.html B.Re ...