如何在 C# 中 运行 可变数量的并发参数化无限循环线程类型?

How do you run a variable number of concurrent parametrizable infinite loop type of threads in C#?

我正在创建我的第一个基于多线程 C#/.NET 的应用程序,它将 运行 在 Azure Service Fabric 集群上。正如标题所说,我希望 运行 可变数量的并发参数化 infinite-loop 类型的线程,这将利用 RunAsync 方法。

每个 child 线程看起来像这样:

        public async Task childThreadCall(...argument list...)
        {
            while (true)
            {
                try
                {
                    //long running code
                    //do something useful here
                    //sleep for an independently parameterizable period, then wake up and repeat
                }
                catch (Exception e)
                {
                    //Exception Handling
                }
            }
        }

在 RunAsync 方法中调用了数量可变的 child 线程。我想做这样的事情:

        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                for (int i = 0; i < input.length; i++)
                {
                    ThreadStart ts[i] = new ThreadStart(childThreadCall(...argument list...));
                    Thread tc[i] = new Thread(ts);
                    tc[i].Start();
                }
            }
            catch (Exception e)
            {
                //Exception Handling
            }
        }

所以基本上每个 child 线程 运行 独立于其他线程,并且永远保持这样做。有可能做这样的事情吗?有人能指出我正确的方向吗?有什么需要注意的陷阱吗?

RunAsync 方法在服务启动时调用。所以是的,它可以用来做你想做的事。我建议使用 Tasks,因为它们与取消标记配合得很好。这是一个草稿:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    var tasks = new List<Task>();
    try
    {
        for (int i = 0; i < input.length; i++)
        {
            tasks.Add(MyTask(cancellationToken, i);
        }
        
        await Task.WhenAll(tasks);
    }
    catch (Exception e)
    {
        //Exception Handling
    }
}

public async Task MyTask(CancellationToken cancellationToken, int a)
{
    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        try
        {
            //long running code, if possible check for cancellation using the token
            //do something useful here
            await SomeUseFullTask(cancellationToken);
            
            //sleep for an independently parameterizable period, then wake up and repeat
            await Task.Delay(TimeSpan.FromHours(1), cancellationToken);
        }
        catch (Exception e)
        {
            //Exception Handling
        }
    }
}

关于陷阱,在使用 Tasks 时通常需要考虑很多 list 事情。

请注意任务最适合 I/O 绑定工作。如果你能 post 在漫长的 运行 过程中到底做了什么,请做,那么我也许可以改进答案以最适合你的用例。

注意传递给 RunAsync 方法的取消令牌很重要,因为它表示服务即将停止。它使您有机会优雅地停止工作。来自 the docs:

Make sure cancellationToken passed to RunAsync(CancellationToken) is honored and once it has been signaled, RunAsync(CancellationToken) exits gracefully as soon as possible. Please note that if RunAsync(CancellationToken) has finished its intended work, it does not need to wait for cancellationToken to be signaled and can return gracefully.

正如您在我的代码中看到的那样,我将 CancellationToken 传递给子方法,以便它们可以对可能的取消做出反应。在你的情况下,取消,因为无限循环。