C# Task.Factory.StartNew 与 Task.Factory.FromAsync

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17432306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:29:05  来源:igfitidea点击:

Task.Factory.StartNew vs Task.Factory.FromAsync

c#.netasynchronoustask-parallel-library

提问by soleiljy

Let's suppose we have a I/O bound method (such as a method making DB calls). This method can be run both in synchronously and asynchronously. That is,

假设我们有一个 I/O 绑定方法(例如进行 DB 调用的方法)。此方法可以同步和异步运行。那是,

  1. Sync:

    IOMethod()
    
  2. Async:

    BeginIOMethod()
    EndIOMethod()
    
  1. 同步:

    IOMethod()
    
  2. 异步:

    BeginIOMethod()
    EndIOMethod()
    

Then when we execute the method in different ways as shown below, what's the performance difference in terms of the resource utilization?

那么当我们以如下所示的不同方式执行该方法时,在资源利用率方面的性能差异是什么?

  1. var task = Task.Factory.StartNew(() => { IOMethod(); });
    task.Wait();
    
  2. var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
    task.Wait();
    
  1. var task = Task.Factory.StartNew(() => { IOMethod(); });
    task.Wait();
    
  2. var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
    task.Wait();
    

采纳答案by svick

var task = Task.Factory.StartNew(() => { IOMethod(); });
task.Wait();

This will block a thread pool thread while IOMethod()is executing and also block your current thread because of the Wait(). Total blocked threads: 2.

这将在IOMethod()执行时阻塞线程池线程,并且由于Wait(). 总阻塞线程数:2。

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
task.Wait();

This will (most likely) perform the operation asynchronously without using a thread, but it will block the current thread because of the Wait(). Total blocked threads: 1.

这将(最有可能)在不使用线程的情况下异步执行操作,但由于Wait(). 总阻塞线程数:1。

IOMethod();

This will block the current thread while IOMethod()is executing. Total blocked threads: 1.

这将在IOMethod()执行时阻塞当前线程。总阻塞线程数:1。

If you need to block the current thread, or if blocking it is okay for you, then you should use this, because trying to use TPL won't actually give you anything.

如果你需要阻塞当前线程,或者如果阻塞它对你来说是可以的,那么你应该使用它,因为尝试使用 TPL 实际上不会给你任何东西。

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
await task;

This will perform the operation asynchronously without using a thread, and it will also wait for the operation to complete asynchronously, thanks to await. Total blocked threads: 0.

这将在不使用线程的情况下异步执行操作,并且由于await. 被阻塞的线程总数:0。

This is what you should use if you want to take advantage of asynchrony and you can use C# 5.0.

如果您想利用异步性并且可以使用 C# 5.0,那么这就是您应该使用的。

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ... );
task.ContinueWith(() => /* rest of the method here */);

This will perform the operation asynchronously without using a thread, and it will also wait for the operation to complete asynchronously, thanks to ContinueWith(). Total blocked threads: 0.

这将在不使用线程的情况下异步执行操作,并且由于ContinueWith(). 被阻塞的线程总数:0。

This is what you should use if you want to take advantage of asynchrony and you can't use C# 5.0.

如果您想利用异步并且不能使用 C# 5.0,那么您应该使用它。

回答by Timothy Shields

(1) will (likely) cause the .NET thread pool to process your Task.

(1) 将(可能)导致 .NET 线程池处理您的Task.

(2) will use whatever mechanism your BeginIOMethod/ EndIOMethodpair natively uses to handle the asynchronous part, which may or may not involve the .NET thread pool.

(2) 将使用您的BeginIOMethod/EndIOMethod对本机使用的任何机制来处理异步部分,这可能涉及也可能不涉及 .NET 线程池。

For example, if your BeginIOMethodis sending a TCP message across the internet, and at a later time the recipient is going to send you a TCP message in response (received by EndIOMethod), then the asynchronous nature of the operation is not being provided by the .NET thread pool. The TCP library being used is providing the asynchronous part.

例如,如果您BeginIOMethod通过 Internet 发送 TCP 消息,稍后接收方将向您发送 TCP 消息作为响应(由 接收EndIOMethod),则 . NET 线程池。正在使用的 TCP 库提供异步部分。

This can be accomplished by using the TaskCompletionSourceclass. Task.Factory.FromAsynccan create a TaskCompletionSource<T>, return its Task<T>, then use EndIOMethodas a trigger to place the Resultinto the Task<T>that was returned form Task.Factory.FromAsyncat the time of calling.

这可以通过使用TaskCompletionSource来完成。Task.Factory.FromAsync可以创建一个TaskCompletionSource<T>,返回其Task<T>,然后EndIOMethod用作触发器将Result放入调用时Task<T>返回的表单Task.Factory.FromAsync中。

What's the performance difference in terms of the resource utilization?

在资源利用率方面的性能差异是什么?

The difference between (1) and (2) is primarily just whether the .NET thread pool is going to have its workload added to or not. In general, the correct thing to do is to choose Task.Factory.FromAsyncif you only have a Begin.../ End...pair and Task.Factory.StartNewotherwise.

(1) 和 (2) 之间的区别主要在于 .NET 线程池是否要添加其工作负载。一般来说,正确的做法是选择Task.Factory.FromAsync是否只有Begin.../End...对,Task.Factory.StartNew否则选择。



If you're using C# 5.0, then you should be using the non-blocking await task;instead of task.Wait();. (See svick's answer.)

如果您使用的是 C# 5.0,那么您应该使用非阻塞await task;而不是task.Wait();. (请参阅 svick 的回答。)