首页 新闻 搜索 专区 学院

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

0
悬赏园豆:200 [已解决问题] 解决于 2021-07-07 17:19

我写了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才能恢复到立马开始,这是为什么呢,感谢帮助!

tossorrow的主页 tossorrow | 初学一级 | 园豆:16
提问于:2021-04-13 11:59
< >
分享
最佳答案
0

我猜啊,Task.Run本质上应该是线程池,如果当前线程池在忙(就是所有线程都在用),那么新的任务就会等待,等到空闲的线程。

收获园豆:100
TidyScript | 菜鸟二级 |园豆:294 | 2021-04-13 15:06
其他回答(5)
0

return await Task.Run(() => ,你这样写就可以了,再把方法加上修饰符async,这杨就不会出现这种情况了

TIAMOLZJ | 园豆:202 (菜鸟二级) | 2021-04-14 17:25
0

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

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

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

tossorrow | 园豆:16 (初学一级) | 2021-04-16 15:26
0

1.服务器的资源利用情况如何?
2.是否设置了线程池的上限(设置过小。)改大一点
3.async await 要链式调用,FileToDataAsync 建议改成 async await模式。(不清楚问题是否和这个有关系)

收获园豆:100
gt1987 | 园豆:1095 (小虾三级) | 2021-04-19 15:17
0

去掉静态方法,改成实例调用呢?

苏秦与真相 | 园豆:211 (菜鸟二级) | 2021-04-21 10:23
0

楼主找到原因了吗

灬丶 | 园豆:4 (初学一级) | 2021-04-25 16:24

原因见thread pool starvation那条评论

支持(0) 反对(0) tossorrow | 园豆:16 (初学一级) | 2021-04-26 09:17
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册