为什么Task.Run要几分钟才能开始?

我写了winform应用, 环境是 windows10, .NET4.6.1.
我添加了一个按钮用于读取硬盘上的文件,并且定义了Task.Run用子线程来读取文件,代码如下:

private async void ReadFileFromHardDisk_Click(object sender, EventArgs e)
{
   var path = Application.StartupPath + $"\\Recipe\\{currentUnit}";
   if (!Directory.Exists(path))
   {
      Directory.CreateDirectory(path);
   }
   OpenFileDialog dialog = new OpenFileDialog();
   dialog.InitialDirectory = path;
   dialog.Filter = "(*.recipe)|*.recipe";
   if (dialog.ShowDialog() == DialogResult.OK)
   {
       string fileName = @dialog.FileName;
       DataForm dataForm = await UtilsSerialize.FileToDataAsync<DataForm>(fileName);
       ShowDataFormToUI(dataForm);
   }
}
public class UtilsSerialize
{
   public static Task<T> FileToDataAsync<T>(string fileName)
   {
      WriteLog($"{DateTime.Now:HH:mm:ss} FileToDataAsync<T>({fileName}) ThreadId: 
          {Thread.CurrentThread.ManagedThreadId}\r\n");
      return Task.Run<T>(() =>
      {
         WriteLog($"{DateTime.Now:HH:mm:ss} FileToDataAsync->Task.Run Start {fileName} ThreadId: 
             {Thread.CurrentThread.ManagedThreadId}\r\n");
         try
         {
            using (FileStream fs = new FileStream(fileName, FileMode.Open))
            {
               using (TextReader textReader = new StreamReader(fs, Encoding.Default))
               {
                  JsonSerializer serializer = new JsonSerializer();
                  T res = (T)serializer.Deserialize(textReader, typeof(T));
                  return res;
               }
            }
         }
         catch (Exception ex)
         {
            return default(T);
         }
         finally
         {
            WriteLog($"{DateTime.Now:HH:mm:ss} FileToDataAsync->Task.Run End {fileName} ThreadId: 
                {Thread.CurrentThread.ManagedThreadId}\r\n");
         }
      }
   }
}

 

一开始运行好好的,Task.Run马上就开始了,但是代码跑了一段时间后,问题就来了,日志记录如下:

20:47:09 FileToDataAsync(C:\Users\iei\Desktop\APP\Recipe\3\0315.recipe) ThreadId:1
20:52:07 FileToDataAsync->Task.Run Start C:\Users\iei\Desktop\APP\Recipe\3\0315.recipe ThreadId:4
20:52:07 FileToDataAsync->Task.Run End C:\Users\iei\Desktop\APP\Recipe\3\0315.recipe ThreadId:4

20:50:16 DataToFileAsync(C:\Users\iei\Desktop\APP\Recipe\6\High.recipe) ThreadId:1
20:53:42 DataToFileAsync->Task.Run Start C:\Users\iei\Desktop\APP\Recipe\6\High.recipe ThreadId:17
20:53:42 DataToFileAsync->Task.Run End C:\Users\iei\Desktop\APP\Recipe\6\High.recipe ThreadId:17

20:53:11 FileToDataAsync(C:\Users\iei\Desktop\APP\Recipe\2\0315.recipe) ThreadId:1
20:55:12 FileToDataAsync->Task.Run Start C:\Users\iei\Desktop\APP\Recipe\2\0315.recipe ThreadId:30
20:55:12 FileToDataAsync->Task.Run End C:\Users\iei\Desktop\APP\Recipe\2\0315.recipe ThreadId:30

Task.Run这下要几分钟之后才能开始了. 只有重启winform应用,Task.Run才能恢复到立马开始,这是为什么呢,感谢帮助!

看代码没什么问题,但是按你说的这个现象,你的应用还有其他地方用到了Task.Run,通过此方法,代码通过线程池执行,很明显,线程池无空闲线程可以使用,所以过好久才开始执行

听说Task.Run得不到线程池分配的线程,这个现象叫thread pool starvation。

简单处理的话有两种思路,一是利用ThreadPool.SetMinThreads方法提高最小并发线程数量。二是长期运行(比如与应用生命周期相同)的Task,用Task.Factory.StartNew方法创建时,设置为TaskCreationOptions.LongRunning。

进一步处理的话,可以自己继承TaskScheduler,自己来控制线程池执行任务。详细参见这位高手的系列文章,https://www.cnblogs.com/s0611163/p/6178973.html