我应该使用线程或者任务 - 多个客户端仿真(Should I use Threads or Task

2019-07-28 20:26发布

我写在所有模拟客户端执行针对服务器的一些预定义的例程的客户端模拟程序 - 这是在蔚蓝的四个实例上运行的Web服务器。

所有模拟客户端建立连接到服务器后,运行相同的程序。

在任何时候,我想用我的程序来模拟300到800的客户端。

我的问题是:我应该创建客户端类的N个实例在N个不同的线程运行呢? 要么

我应该使用任务库做的事情?

Answer 1:

你当然不应该创建800个线程。

让我们退后一步,在这里。 您有一个名为“服务器”这需要从“客户”,“请求”,并发出“回应”回这些客户端设备。 让我们假设该请求是通过邮局递送的纸片,并答复是包含书籍,还通过邮局递送盒。

您希望模拟 800级的客户,以测试服务器。

让我们假设一个线程是一个人,一个处理器是椅子。 一个人只能做工作,而坐在椅子上。

创建800个线程是走出去,招聘800人,并支付他们每人寄一封信到服务器的等价物。 但你只有四把椅子,让那些800人必须采取一切用椅圈。

这将是在现实生活中可笑的解决方案。 线程,喜欢的人,都出奇的贵 。 你应该尽量减少你创建的线程数。

所以,你应该改为通过任务工厂创造800个任务,让TPL并行他们的吗?

不,你不应该这样做,要么。 该TPL拥有人(线程)的池借鉴和尝试,以便有没有更多的人对工资之外还有椅子让他们坐,安排的事情,但你的任务不是“椅子约束。” - - 人们会在椅子上坐下,将请求发送到服务器,然后从椅子上站,而他们等待响应回来。 当他们在等待,现在TPL不得不雇用更多的人来服务的额外任务。

创下了Web服务器的I / O绑定; 你应该只对那些CPU密集型任务创建线程池的任务。

正确的解决办法是聘请了两个人。

一个人 - 在“I / O完成线程” - 什么都不做,但在邮箱下降请求,并检查传入的包。 其他人 - 在“模拟”的人 - 工作了什么是正确的“时间表”是用于模拟800级的客户端。 模拟人的工作出了时间表,然后进入睡眠状态。 她醒来的时候,是时候发送另一个请求到服务器。 当她醒来时,她讲述了I / O完成线程砸在邮箱这封信,她叫醒当响应进来,然后她回去睡觉,直到是时候再次提出请求或响应谈到在需要进行验证。

你应该做的是:(1)获得的C#5和使用的测试版async/await创建发送请求到服务器的任务,然后得到控制回消息循环,直到是时候再次提出请求或响应进来。或者,如果你不想使用C#5,您应该创建一个任务完成源,并设置有合适的延续任务。

总之:要处理很多并行I / O任务的正确方法是创建一个非常小的数目的线程,每一个在同一时间做工作的一个非常小的量。 让I / O完成线程处理I / O的详细信息。 你并不需要聘请800人,以模拟发送800封。 聘请两个人,一个看热闹的邮箱和一个写字母。



Answer 2:

在这种情况下,答案并非如此简单。 这真的取决于你要如何模拟你的客户:

  1. 如果你想拥有800级连接的客户端,但不一定在同一时间,它的使用是一个好主意Task秒。 他们是重量轻,有效地利用底层的ThreadPool

  2. 如果你真的想客户是绝对的所有并行,恐怕是没有办法真正避免线程。 有没有神奇的办法让800个轻巧同时执行任务。 该Task的抽象是轻量级的,正是因为它使用线程池。 这意味着许多任务都映射到少量的实际线程。 但是,当然,这意味着他们没有真正的并行运行,而是将计划运行只要有可能。 该ThreadPool有(据我所知)250的最大线程数,所以不超过250个“客户”实际上将在同一时间执行,如果你使用Task秒。 该解决方案设置最大线程数到800,但在这一点上它与使用经典的线程。



Answer 3:

我会用任务库,让任务库处理所有的线程为您服务。 你不想旋转起来800个线程。 它是一个坏主意,有许多并发线程去的时间,这里是谈论另一个堆栈溢出问题: 最大线程数在.NET应用程序?



Answer 4:

对于这种应用领域是你最好的选择。

应用程序域是隔离在.NET应用程序执行的运行时单元。 它提供了一个管理存储器边界,对应用程序配置设置的容器,以及用于分布式应用程序提供的通信接口。

每个.NET应用程序通常承载由所述CLR给定进程/程序启动时自动创建一个应用领域。 它是有用的某个时候(在如你的情况)与在单一过程/程序创建额外的应用程序域。 使用多个应用程序域避免通信并发症出现使用几个单独的流程,并提供你的任务隔离。

你想要的东西,你有两个选择。

  1. 在同一个域起始于单独的线程X线。

这将意味着你将有非常疲乏的是线程安全的,这将是非常困难的这样一个任务,模拟多次登录,模拟客户端等。

  1. 每个在其自己的应用程序域相同的进程启动X线。

这将让每一个孤立的纺线,也容易被托管的应用程序/程序来访问的。 通过具有各位X模拟在X单独的应用程序域,每个域将被分离,并无法通过静态类成员等另一客户端仿真干扰

由来自约瑟夫阿尔巴哈利的书的摘录辅助下C#4.0简而言之 ,我强烈建议得到:

40个并发客户端模拟一个例子可能是对你有用的:

class program
{
    static void main()
    {
        // Create 40 domains and 40 threads.
        AppDomain[] domains = new AppDomain[40];
        Thread[] thread = new Thread[40];

        for (int i = 0; i < 40; i++)
        {
            domains[i] = AppDomain.CreateDomain("Client Simulation " + i);
            thread[i] = new Thread(SimulateClientInOtherDomain);
        }

        // Start all threads, passing to each thread its app domain.
        for (int j = 0; j < 40; j++)
            threads[j].Start(domains[j]);

        // Wait for the threads to finish.
        for (int k = 0; k < 40; k++)
            threads[k].Join();

        // Unload the application domains.
        for (int l = 0; l < 40; l++)
            AppDomain.Unload(domains[l]);
    }

    // Thread start with input of with domain to run on/in.
    static void SimulateClientInOtherDomain(object domain)
    {
        ((AppDomain)domain).DoCallBack(Simulate);
    }

    static void Simulate()
    {
       Client simClient1 = new Client("Bill", "Gates", ...);
       simClient1.Simulate();
    }
}

我希望这有帮助。



文章来源: Should I use Threads or Tasks - Multiple Client Simulation