【问题标题】:Maximum number of Threads available to Tasks任务可用的最大线程数
【发布时间】:2017-01-06 11:20:11
【问题描述】:

我正在尝试了解 C# 中的 async-await 功能。我编写了下面的代码来异步运行多个任务 - 目前他们所做的只是在一定时间后引发一个事件。

public class Program
{
    public static Stopwatch Watch = new Stopwatch();

    public static void Main(string[] args)
    {
        AsyncClass asyncClass = new AsyncClass();
        asyncClass.WaitSecondsAsyncCompleted += asyncClass_WaitSecondsAsyncCompleted;
        List<Task> tasks = new List<Task>();
        Watch.Start();
        for (int i = 1; i < 6; i++)
        {
            tasks.Add(asyncClass.WaitSecondsAsync(i, Watch));
        }
        Task.WaitAll(tasks.ToArray());
        Console.ReadLine();
    }

    private static void asyncClass_WaitSecondsAsyncCompleted(int i)
    {
        Console.WriteLine("{1} : Async Method Called: waited for {0} seconds", i, Watch.ElapsedMilliseconds);
    }
}

public class AsyncClass
{
    public event Action<int> WaitSecondsAsyncCompleted;

    public async Task WaitSecondsAsync(int x, Stopwatch watch)
    {
        await Task.Run(() =>
        {   
            Thread.Sleep(x * 500); 
        });

        if (WaitSecondsAsyncCompleted != null)
        {
            WaitSecondsAsyncCompleted(x);
        }
    }
}

我希望大约每半秒完成一次任务——但这并不是我所看到的。相反,前四个任务按时完成,但最后一个任务有额外的半秒延迟:

这看起来很奇怪——我唯一能想到的是,一个任务可用的线程数是有限制的,这个限制非常小,所以第五个任务必须等待在开始之前完成第一个任务。

我添加了一些额外的输出并增加了任务的数量以尝试获取更多信息,但我无法理解它 - 输出似乎是确定性的,一些线程被重用,但也使用了新线程。完成任务的延迟似乎也在继续增长(例如,对于任务 10,我希望它在 5 秒后完成,而不是在 8 秒后停止)。我附上了下面的输出。

我想知道的:

  • 有人知道这个特定示例中发生了什么吗?
  • 可用线程的限制是否小到足以在此处产生影响?
  • 我认为异步任务不能保证立即启动,但这里似乎还有一些其他确定性过程正在进行,这是我没有预料到的。有人知道那是什么吗?


编辑

请注意,此问题不是询问可以运行的最大任务数 (Max tasks in TPL?),而是询问在运行 5 个任务时如何看到效果。我的印象是默认线程池包含比这更多的线程。

【问题讨论】:

  • Max tasks in TPL?的可能重复
  • 你有四个核心吗?
  • 是的,它确实有 4 个内核 - 请注意我发布的第二个屏幕截图,虽然最初它似乎被限制为 4 个线程,但后来这个数字会增加,以便同时运行更多任务。
  • 您可能希望为每个任务创建单独的秒表,并添加开始时间的显示。这也可以让您深入了解任务的启动时间。
  • 另外,忘记线程。它们只是一个实现细节。异步操作(有时)可以在没有任何额外线程的情况下运行。阅读this article called 'There is no thread'

标签: c# multithreading async-await task threadpool


【解决方案1】:

所以,事实证明我看到的问题与线程池大小有关。这显然最初设置为机器的核心数(https://msdn.microsoft.com/en-us/library/system.threading.threadpool.getminthreads%28v=vs.110%29.aspx)。

可以增加,这样做意味着最初同时运行更多任务 (https://msdn.microsoft.com/en-us/library/system.threading.threadpool.setminthreads%28v=vs.110%29.aspx)

【讨论】:

  • 为了完整起见,我想补充一点,在大多数情况下建议使用SetMaxThreads 设置线程池大小。此设置是针对每个进程的:其他进程不受影响,但您的整个应用程序会受到影响。许多 TPL 原语(PLINQ、Parallel.*)允许您设置最大并行度。感谢this SO answer
猜你喜欢
  • 1970-01-01
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
  • 2016-09-14
相关资源
最近更新 更多