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. SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换

    http://blog.sina.com.cn/s/blog_5aee9eaf0100y44q.html 在CentOS6.2 中安装intel 的c++和fortran 的编译器时,遇到来一个关于S ...

  2. linux中$@,$*,$0,$$,$?参数的含义

    $# 是传给脚本的参数个数 $ 是脚本本身的名字 $ 是传递给该shell脚本的第一个参数 $ 是传递给该shell脚本的第二个参数 $@ 是传给脚本的所有参数的列表 $* 是以一个单字符串显示所有向 ...

  3. ajax封装最后形态

    function obj1(obj) { obj.t = new Date().getTime(); var res = []; for (var key in obj) //url中不能出现中文 r ...

  4. 利用IDEA构建springboot应用-如何优雅的使用mybatis

    orm框架的本质是简化编程中操作数据库的编码 一个是宣称可以不用写一句SQL的hibernate, 一个是可以灵活调试动态sql的mybatis mybatis-spring-boot-starter ...

  5. Python基础:18类和实例之二

    1:绑定和非绑定 当存在一个实例时,方法才被认为是绑定到那个实例了.没有实例时方法就是未绑定的.在很多情况下,调用的都是一个绑定的方法. 调用非绑定方法并不经常用到,其中一个主要的场景是:派生一个子类 ...

  6. 2018-8-10-添加右键使用-SublimeText-打开

    title author date CreateTime categories 添加右键使用 SublimeText 打开 lindexi 2018-08-10 19:16:52 +0800 2018 ...

  7. oracle函数 RTRIM(c1,[,c2])

    [功能]删除右边出现的字符串 [参数]C1 字符串 c2 追加字符串,默认为空格 [返回]字符型 [示例] SQL> select RTRIM('gao qian jingXXXX','X') ...

  8. 权值线段树+动态开点[NOI2004]郁闷的出纳员

    #include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> ...

  9. Install Openjdk11 to Ubuntu 18.04 LTS

      Ubuntu 18.04 LTS系统上通过sudo apt install openjdk-11-*命令安装的jdk11版本依然是jdk10,怎么样才能安装openjdk 11呢,今天,我们就来完 ...

  10. H3C 主机单播IP包发送