简体   繁体   English

.Net Core 中的多线程 Worker 服务

[英]Multi Thread Worker Service in .Net Core

I'm trying build a worker service on Core 5.0.我正在尝试在 Core 5.0 上构建一个工作服务。 My tree is basically like that =>我的树基本上就是这样=>
1 -) Program.cs 2-) Worker.cs 3-) MyStartUp.cs 4-) Client.cs 1-) Program.cs 2-) Worker.cs 3-) MyStartUp.cs 4-) Client.cs

In MyStartUp.cs I am getting a list and calling Client class some servers according to list.在 MyStartUp.cs 我得到一个列表并根据列表调用客户端类一些服务器。
In the Client class, I connect to the devices and write the data I read to the database.在 Client 类中,我连接到设备并将读取的数据写入数据库。
Device count nearly 1200, server way is TCP/IP.设备数近1200台,服务器方式为TCP/IP。
What is your best suggestion for write a worker service like that?对于编写这样的工作人员服务,您最好的建议是什么? How can I use threads in it best form?如何以最佳形式使用线程?

Below is my first try.下面是我的第一次尝试。 This form is working but it's so slow for 1000 different client because there is so much reads in client.这种形式是有效的,但是对于 1000 个不同的客户端来说太慢了,因为客户端中有太多的读取。

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        StartUp startUp = new StartUp();
    }
}

public class StartUp
{
    public StartUp()
    {
        //... get client datas and initialize client object
        StartClients();
    }
    public void StartClients()
    {
        foreach (var item in ClientList)
        {
            new Thread(item.Run).Start();
        }
    }
}

public class Client
{
    System.Timers.Timer timer ;
    public Client()
    {
        timer = new Timer();
        timer.Interval = 100;
        timer.Elapsed += Timer_Elapsed;
        
        //... initialize client connection and database
    }
    public void Run()
    {
        timer.Start();
    }
    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //... write values of read client to database
    }
}

Say that you have 1k timers that run every 100ms, and say that each timer tick takes 50ms to execute.假设您有 1k 个每 100 毫秒运行一次的计时器,并假设每个计时器滴答需要 50 毫秒来执行。 That means each timer needs 500ms/s, or 50% of one core, and you would need 500 cores to keep up with the work.这意味着每个计时器需要 500 毫秒/秒,或一个内核的 50%,而您需要 500 个内核来跟上工作。 You probably do not have that many cores, nor IO to process the requests, and that means the work will start piling up and your computer will more or less freeze since it does not have time to update the UI.您可能没有那么多内核,也没有 IO 来处理请求,这意味着工作将开始堆积,您的计算机将或多或少地冻结,因为它没有时间更新 UI。

50ms might be an overestimation of the time used, but even at 5ms you would probably have issues unless you are running this on a monster server. 50 毫秒可能高估了所用时间,但即使是 5 毫秒,除非您在怪物服务器上运行它,否则您可能会遇到问题。

The solution would be to decrease the polling frequency to something more reasonable, say every 100s instead of every 100ms.解决方案是将轮询频率降低到更合理的频率,例如每 100 秒而不是每 100 毫秒。 Or to have one or more threads that polls your devices as fast as they can.或者让一个或多个线程尽可能快地轮询您的设备。 For example something like:例如:

private BlockingCollection<MyClient> clients = new ();
private List<Task> workers = new ();
public void StartWorker(){
    workers.Add(Task.Run(Run));
    void Run(){
        foreach(var client in clients.GetConsumingEnumerable()){
           // Do processing
           clients.Add(client); // re-add client to queue
      }
   } 
}
public void CloseAllWorkers(){
    clients.CompleteAdding();
    Task.WhenAll(workers).Wait();
}

I would note that usages of Thread is mostly superseded by tasks.我会注意到Thread的使用主要被任务所取代。 And that creating a thread just to start a System.Timers.Timer is completely useless since the timer will run the tick event on the threadpool, regardless of the thread that started it.并且创建一个线程只是为了启动System.Timers.Timer是完全没用的,因为计时器将在线程池上运行滴答事件,而不管启动它的线程是什么。 At least unless a synchronization object was specified.至少除非指定了同步对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM