首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当我需要可伸缩性时,我不应该使用TPL吗?

当我需要可伸缩性时,我不应该使用TPL吗?
EN

Stack Overflow用户
提问于 2014-04-16 06:28:59
回答 1查看 609关注 0票数 1

线程池线程是重要的可重用线程(例如,在asp.net中)-帮助服务请求。

相对于不使用线程池线程且不支持取消令牌、连续性和结果值的原始new Thread().start(....),毫无疑问,TPL是首选策略。

但问题是,Task 也是 uses线程池线程。

在TPL中,TaskScheduler负责将任务排队等待执行。默认调度程序将使用线程池。

这让我很好奇:

假设我有一个有许多并发用户的站点,我需要为每个用户执行3个计算绑定任务(非IO)。

恐怕线程池将没有线程了(因为我将通过使用线程池线程的任务执行3计算操作(针对每个用户)。-这将导致创建新的线程池线程。

这使我得出这样的结论:当我需要可伸缩性时,最好使用旧的时尚new Thread().start(...)

我遗漏了什么?我们回到原点了吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-16 06:57:28

您很少需要在Task.RunTask.Factory.StartNew中使用ASP.NET,这些app都用于与CPU绑定的工作,在处理HTTP请求时将CPU绑定的工作卸载到另一个线程(与客户端用户界面应用程序不同)通常是没有意义的。这只会损害可伸缩性。只需在当前线程上进行工作即可。

如果您需要在多个HTTP请求中生成一个具有生存期的长期运行任务,请使用@Damien_The_Unbeliever在注释中建议的单独进程,例如同一主机上的WCF服务或单独的主机。

也就是说,您仍然可以将一个非池线程包装为Task,包含所有的好处,至少在当前的TPL实现中是这样的。它是在TaskCreationOptions.LongRunningTask.Factory.StartNew一起使用时创建的。在这样的线程中,Thread.IsThreadPoolThread将是false。这可能会防止ThreadPool饥饿,但肯定会增加进程的工作集。此外,这些线程不像ThreadPool线程那样被TPL重用,因此重复创建非池线程可能成本很高。

作为TaskCreationOptions.LongRunning的另一种选择,使用TaskCompletionSourcenew Thread().Start()包装为Task很容易,具有相同的取消、异常和结果传播逻辑。

另一个想法是使用自定义任务调度程序,它总是将任务排在一个新线程上:

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(new { Thread.CurrentThread.ManagedThreadId });

        var task = Task.Factory.StartNew(
            () => Console.WriteLine(new { 
                Thread.CurrentThread.IsThreadPoolThread,
                Thread.CurrentThread.ManagedThreadId}),
            CancellationToken.None,
            // hide the scheduler from inner tasks
            TaskCreationOptions.HideScheduler,
            NewThreadTaskScheduler.Scheduler);

        task.Wait();
    }
}

class NewThreadTaskScheduler : TaskScheduler
{
    public static readonly NewThreadTaskScheduler Scheduler = 
        new NewThreadTaskScheduler();

    NewThreadTaskScheduler()
    {
    }

    protected override void QueueTask(Task task)
    {
        var thread = new Thread(() =>
        {
            base.TryExecuteTask(task);
        });
        thread.IsBackground = true;
        thread.Start();
    }

    protected override bool TryExecuteTaskInline(
        Task task, 
        bool taskWasPreviouslyQueued)
    {
        return false;
    }

    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return null;
    }

    public override int MaximumConcurrencyLevel { 
        get { return Int32.MaxValue; } }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23101686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档