Task 有没有类似线程池的说法?让某些Task方法在执行结束后保留线程,而不是每次执行都创建新的线程?

boyyao 2021-04-25 12:25:14
前几天折腾并行运算。在wanghui0380等大神的帮助下。折腾的差不多了。但是后来发现用task来多线程并行处理一些东西后。如果一段时间没有调用(几秒-数十秒左右)这个task方法后再次调用实行速度会慢很多。。。连续执行则没有这个问题。观察发现是并行处理的Task的线程启动/自动退出导致的。

本想通过线程池来尝试能否解决。但是由于现在程序结构都是用task来做的。所以想在改动程序较少的情况下。task能否完成类似的功能?使得一些线程得以保留?
原始代码大概如下:

public static Task TestTask(int Index)
{
Task task1 = Task.Run(() =>
{
//较高耗时过程。。
return;
});
return task1;
}




Parallel.For(0, 6, new ParallelOptions() { MaxDegreeOfParallelism = 6 }, async (i) =>
{
await TestTask(i);
});

Console.WriteLine($"结束");



另外一个问题 Console.WriteLine($"结束"); 总是被提早执行了。没有等到Parallel.For处理完成。 如上用 async (i) 也是如此?请问应该如何解决?
...全文
182 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuzuning 2021-04-25
  • 打赏
  • 举报
回复
Task 是线程池的再包装,请不要去鸡蛋里面挑骨头 async / await 结构是异步回调代码的同步写法 ,是语法糖
wanghui0380 2021-04-25
  • 打赏
  • 举报
回复
我们来看,task策略的其中一个 PreferFairness:提示TaskScheduler以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。 尽量公平--------------------------只是尽量公平,不是绝对公平 这意味着较早安排的任务将更可能较早运行---------------------较早有更大可能被提前调度,只是可能,尽可能被提前调度 而较晚安排运行的任务将更可能较晚运行。--------------------------一样的口吻,他大概率会被延后调度,但是只是说大概率延后
wanghui0380 2021-04-25
  • 打赏
  • 举报
回复
同样从池上的使用来说,也会要求你尽量拆成小任务,控制并发数量 池本身有数量,所以如果你无限创建大任务,结果就是线程池满。(要么异常,要么等待) 如果是等待池有释放,当然他会慢 所以还是拿3句话,自己处理。别和博客园那些人一样非名词不会写代码。我们不要名词,无论是线程也好,还是线程池也好,还是其他的技术 无论你用什么名词写代码,就3条 1.有IO的及时清理内存 2.要计算的,尽量拆成小任务 3.在不影响设计要求的前提下,约束执行数量
wanghui0380 2021-04-25
  • 打赏
  • 举报
回复
至于你第1个问题,其实我们无法解决。 因为你还是陷入到一个误区,你认为线程就是立刻执行,非常执着的追求着“并行处理的Task的线程启动/自动退出导致的。” 其实压根就不是,我们前贴已经告诉你了,线程压根就不存在什么立刻执行的说法。线程有自己的状态:创建,就绪,执行中,挂起中,死亡 系统有线程调度器去调度线程,所以并没有你说的什么启动,自动退出如何如何导致你慢 所以这问题我无法继续说明什么,只能直接给你下结论 1.task本身就是线程池,所以你无需纠结什么线程池问题。他解决了创建问题,也就是他会从池里就近去挑一个死亡状态的线程给你,然后设置为就绪状态,也就是与你自己创建线程相比,线程池的目的就是“约束创建的数量,节省掉创建过程,直接管理就绪,执行,挂起,死亡“ 2.无论task也好,线程也罢,都归线程调度器调度,线程调度器有几个策略 public enum TaskCreationOptions { None = 0, PreferFairness = 1, LongRunning = 2, AttachedToParent = 4, DenyChildAttach = 8, HideScheduler = 16 } 这块你自己看(当然传统线程还有优先级,只是在task体系里,这些优先级被上面那个枚举默认实现,比如longruning的优先级是低优先级) 3.不要纠结与线程不线程,你需要总体看当前“并行线程”,而不是纠结什么线程死啊,生啊。 如果系统当前并行线程1w个,你现在新加的线程是第1w零1个,你觉着现在调度器进行时间片切换调度的时候(我们就打你有8核,你可以同时运行8核线程)有多大几率会在你就绪瞬间,就被调度到这个8个核的其中之一上了,很明显,你并行线程越多,他立刻运行的几率越小 所以我们前面也说了,请在保证业务的基础上控制并发数量,同时请尽量减少单个线程的执行时间(做成小任务) 很明显:如果前面1w都是小任务,很快走掉,比如4个时间片周期走掉8000个,那么你就排位就2001,你就有更大几率被立刻执行 很明显:如果我还控制了并发数量,那么后续加进来的线程会更少,我现在这个也会有更大几率立刻执行
正怒月神 2021-04-25
  • 打赏
  • 举报
回复
看这个就很直观了,肯定底部有线程池。
wanghui0380 2021-04-25
  • 打赏
  • 举报
回复
先解决你后一个问题
  ConcurrentBag<Task> bag = new ConcurrentBag<Task>();  //注意这里请使用线程安全类列表,因为你下面这个并行实际会是多线程的,如果使用list这种非线程安全的列表,会产生意外
Parallel.For(0, 6, new ParallelOptions() { MaxDegreeOfParallelism = 6 },  (i) =>
                {
                         bag.add(TestTask(i));
                });

await Task.WhenAll(bag)
guanyinsishengzi 2021-04-25
  • 打赏
  • 举报
回复
没看明白,已经使用Parallel了,怎么还需要Task。。

 public static voidTestTask(int Index)
        {
                //较高耗时过程。。
        }

Parallel.For(0, 6, new ParallelOptions() { MaxDegreeOfParallelism = 6 }, (i) =>
                {
                        TestTask(i);
                });
 
Console.WriteLine($"结束");

110,572

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧