线程池线程是重要的可重用线程(例如在 asp.net 中) - 有助于服务请求。
与原始 new Thread().start(....)
不同它不使用线程池线程,并且不支持取消 token 、连续性、结果值——毫无疑问,TPL 是首选策略。
但问题是 Task
还有 uses线程池线程。
In TPL, a TaskScheduler is responsible for actually queuing the tasks up for execution. The Default scheduler will use the thread-pool .
这让我想知道:
假设我有一个有许多并发用户的站点,我需要为每个用户执行 3 个计算绑定(bind)任务(非 IO)。
我担心线程池将没有线程剩余(因为我将通过使用线程池线程的 TASK 执行 3 个计算操作(针对每个用户)。 - 这将导致创建新的线程池线程。
这使我得出结论,当我需要可扩展性时 - 最好使用旧式
new Thread().start(...)
?我错过了什么?我们回到第一方了吗?
最佳答案
您很少需要使用 Task.Run
或 Task.Factory.StartNew
在 ASP.NET 中。这些 API 用于 CPU 密集型工作,在处理 HTTP 请求时将 CPU 密集型工作卸载到另一个线程通常没有意义(与客户端 UI 应用程序不同)。那只会损害可扩展性。只需在当前线程上完成工作。
如果您需要跨多个 HTTP 请求生成具有生命周期的长期运行任务,请使用 @Damien_The_Unbeliever 在评论中建议的单独进程,例如,在同一主机或单独主机上的 WCF 服务。
也就是说,您仍然可以将非池线程包装为 Task
所有的好东西,至少在当前的 TPL 实现中。它是在您使用 TaskCreationOptions.LongRunning
时创建的与 Task.Factory.StartNew
.在这样的线程中,Thread.IsThreadPoolThread
将是 false
.这可能会阻止 ThreadPool
饥饿,但肯定会增加进程的工作集。此外,此类线程不会被 TPL 重用,例如 ThreadPool
。线程,因此重复创建非池线程可能会非常昂贵。
作为 TaskCreationOptions.LongRunning
的替代品,很容易包装new Thread().Start()
作为 Task
使用 TaskCompletionSource
,具有相同的取消、异常和结果传播逻辑。
还有一个想法是使用自定义任务调度程序 它总是在一个新线程上排队任务:
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; } }
}
关于c# - 当我需要可扩展性时,我不应该使用 TPL 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23101686/