我要如何转换成一个异步任务吗?我要、转换成、任务

2023-09-03 03:22:21 作者:夜未央い落雪成殇

由于以下code ...

Given the following code...

static void DoSomething(int id) {
    Thread.Sleep(50);
    Console.WriteLine(@"DidSomething({0})", id);
}

我知道我可以转换成一个异步任务如下...

I know I can convert this to an async task as follows...

static async Task DoSomethingAsync(int id) {
    await Task.Delay(50);
    Console.WriteLine(@"DidSomethingAsync({0})", id);
}

和,如果这样做,如果我打电话多次(Task.WhenAll)一切都会变得更快,更高效或许比使用Parallel.Foreach,甚至从一个循环中调用。

And that by doing so if I am calling multiple times (Task.WhenAll) everything will be faster and more efficient than perhaps using Parallel.Foreach or even calling from within a loop.

不过一分钟,让pretend的Task.Delay()不存在了,我实际上使用了Thread.Sleep();我知道在现实中不是这种情况,但这是概念code和其中所述延迟/睡眠是通常是一个IO操作在没有async选项(如早期,EF)。

But for a minute, lets pretend that Task.Delay() does not exist and I actually have to use Thread.Sleep(); I know in reality this is not the case, but this is concept code and where the Delay/Sleep is would normally be an IO operation where there is no async option (such as early EF).

我曾尝试以下...

static async Task DoSomethingAsync2(int id) {
    await Task.Run(() => {
        Thread.Sleep(50);
        Console.WriteLine(@"DidSomethingAsync({0})", id);
    });
}

不过,尽管它运行没有错误,根据Lucien Wischik 这实际上是不好的做法,因为它仅仅起转线程池中完成每个任务(这也是慢用下面的控制台应用程序 - 如果你换DoSomethingAsync和DoSomethingAsync2之间的呼叫,你可以看到一个显著差异因为它需要完成的时间)...

But, though it runs without error, according to Lucien Wischik this is in fact bad practice as it is merely spinning up threads from the pool to complete each task (it is also slower using the following console application - if you swap between DoSomethingAsync and DoSomethingAsync2 call you can see a significant difference in the time that it takes to complete)...

static void Main(string[] args) {
    MainAsync(args).Wait();
}

static async Task MainAsync(String[] args) {

    List<Task> tasks = new List<Task>();
    for (int i = 1; i <= 1000; i++)
        tasks.Add(DoSomethingAsync2(i)); // Can replace with any version
    await Task.WhenAll(tasks);

}

然后我尝试了以下...

I then tried the following...

static async Task DoSomethingAsync3(int id) {
    await new Task(() => {
        Thread.Sleep(50);
        Console.WriteLine(@"DidSomethingAsync({0})", id);
    });
}

代替原来DoSomethingAsync移栽这一点,测试永远不会完成,并没有显示在屏幕上!

Transplanting this in place of the original DoSomethingAsync, the test never completes and nothing is shown on screen!

我也试过,要么不编译或没有完成多个其它的变化!

I have also tried multiple other variations that either do not compile or do not complete!

所以,既然你不能调用任何现有的异步方法,必须以异步任务既完成了Thread.Sleep和Console.WriteLine命令约束,你怎么做到这一点的方式是一样有效,原来的code吗?

So, given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task, how do you do it in a manner that is as efficient as the original code?

我们的目标在这里为那些你们谁感兴趣的是给我一个更好地了解如何创建自己的异步方法,我不是要求别人的人。尽管有许多的搜索,这似乎是一个领域的例子是真正缺乏的 - 虽然有成千上万的调用调用其他异步方法异步方法的例子反过来我找不到任何现有的无效方法转换为异步任务在哪里有进一步的异步任务比那些使用Task.Run其他没有呼叫(()=> {})方法

The objective here for those of you who are interested is to give me a better understanding of how to create my own async methods where I am not calling anybody elses. Despite many searches, this seems to be the one area where examples are really lacking - whilst there are many thousands of examples of calling async methods that call other async methods in turn I cannot find any that convert an existing void method to an async task where there is no call to a further async task other than those that use the Task.Run(() => {} ) method.

推荐答案

有两种类型的任务:那些执行code(例如, Task.Run 和朋友),而那些以一些外部事件做出响应(例如, TaskCompletionSource&LT; T&GT; 和朋友)

There are two kinds of tasks: those that execute code (e.g., Task.Run and friends), and those that respond to some external event (e.g., TaskCompletionSource<T> and friends).

您正在寻找的是 TaskCompletionSource&LT; T&GT; 。有各种各样的速记形式常见的情况,所以你并不总是需要使用 TaskCompletionSource&LT; T&GT; 直接。例如, Task.FromResult TaskFactory.FromAsync FromAsync 是最常用的,如果你有一个现有的 *开始 / *结束执行您的I / O的;否则,你可以使用 TaskCompletionSource&LT; T&GT; 直接

What you're looking for is TaskCompletionSource<T>. There are various "shorthand" forms for common situations so you don't always have to use TaskCompletionSource<T> directly. For example, Task.FromResult or TaskFactory.FromAsync. FromAsync is most commonly used if you have an existing *Begin/*End implementation of your I/O; otherwise, you can use TaskCompletionSource<T> directly.

有关详细信息,请参阅的实施基于任务的异步模式。

For more information, see the "I/O-bound Tasks" section of Implementing the Task-based Asynchronous Pattern.

工作构造函数(不幸)的基于任务的并行缓缴,并应在异步code不能使用。它只能用于创建$ C $基于C的任务,而不是一个外部事件任务。

The Task constructor is (unfortunately) a holdover from Task-based parallelism, and should not be used in asynchronous code. It can only be used to create a code-based task, not an external event task.

所以,既然你不能调用任何现有的异步方法,必须以异步任务既完成了Thread.Sleep和Console.WriteLine命令约束,你怎么做到这一点的方式是一样有效,原来的code吗?

So, given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task, how do you do it in a manner that is as efficient as the original code?

我会用某种形式的计时器,并让它完成 TaskCompletionSource&LT; T&GT; 当计时器触发。我几乎可以肯定,这就是实际的 Task.Delay 的实施确实反正。

I would use a timer of some kind and have it complete a TaskCompletionSource<T> when the timer fires. I'm almost positive that's what the actual Task.Delay implementation does anyway.