操作未知时如何等待 Task.Run(action)
How to Await Task.Run(action) when action is unknown
我有以下代码:
static void Main(string[] args)
{
Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));
int count = 5;
do
{
Console.WriteLine(count.ToString());
Thread.Sleep(100);
count++;
} while (count < 20);
Console.ReadKey();
}
private static void LongProcess()
{
Console.WriteLine("Long Process 1");
Thread.Sleep(2000);
Console.WriteLine("Long Process 2");
}
private static void LongerProcess()
{
Console.WriteLine("Longer Process 1");
Thread.Sleep(3000);
Console.WriteLine("Longer Process 2");
}
private static async Task Run(Action action)
{
await Task.Run(action); //shouldn't this wait until the action is completed??
// how should I modify the code so that the program waits until action is done before returning?
}
对于 await Task.Run(action);
,我希望程序会等到 action
完成,然后再继续下一步。换句话说,我期待这样的输出:
Long Process 1
Long Process 2
Longer Process 1
Longer Process 2
5
6
7
8
...
19
然而,输出就像
Long Process 1
5
6
7
8
...
19
Long Process 2
Longer Process 1
Longer Process 2
问题:
- 为什么
await Task.Run
不等到 action
完成?
- 如何更改代码以提供我想要的输出?
使用await
不等待,这就是重点。如果要等待,请使用 Task.Wait
.
但是,async
方法的执行只有在等待的任务完成后才会继续执行(这是一个延续)。让我们看看您的 async
方法:
private static async Task Run(Action action)
{
await Task.Run(action);
// There is nothing here
}
任务完成后没有要执行的代码...好吧,async
方法returns一个任务完成时完成的任务。让我们看看您是否await
...
Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));
你不知道。你解雇了那个任务,然后忘了它。
我想这就是你想要的:
static async void Main(string[] args)
{
await Run(() => LongProcess());
await Run(() => LongerProcess());
int count = 5;
do
{
Console.WriteLine(count.ToString());
Thread.Sleep(100);
count++;
} while (count < 20);
Console.ReadKey();
}
注意:Async Main 是 C# 7.1 的一项功能。
此代码将 运行 调用 LongProcess
的任务,然后作为 运行 调用 LongerProcess
的任务的延续,然后作为延续其余部分代码。
为什么你想要那个而不是仅仅同步调用这些方法我无法理解。
顺便说一下,在 async
方法中,您可以使用 await Task.Delay(milliseconds)
而不是 Thread.Sleep(milliseconds)
。优点是线程不等待。 这就像在单个执行计时器上进行延续。
如果 async/await
只是延续,您可能想知道为什么人们要使用它们而不是 ContinueWith
。
让我给你几个理由:
- 带有
async/await
的代码更易于阅读。更少的嵌套内容使代码变得模糊。您可以独立于理解线程来理解代码的作用。
-
async/await
的代码更容易编写。你只是把它写得好像它们都是同步的,其中有一些 async
和 await
闪闪发光。您可以编写同步代码,然后担心如何使其并发。您最终也会写得更少,这意味着您的工作效率更高。
- 带有
async/await
的代码更聪明™。编译器将您的代码重写为连续状态机,允许您将 await
放入语句中而无需任何代码体操™。这扩展到异常处理。你看,在你的 fire and forget 任务继续中,你没有处理异常。如果 LongerProcess
抛出怎么办?好吧,使用 async/await
,您只需将 await
放在 try ... catch
中,它就会做正确的事情™。
这就是很好的关注点分离。
您可能还想知道在什么情况下使用 async/await
而不是同步代码是个好主意。答案是它在处理 I/O 操作时大放异彩。与外部系统交互时,通常不会立即得到响应。例如,如果你想从磁盘读取或从网络下载。
事实上,如果您考虑将操作表单和处理其事件视为 I/O 绑定操作(因为,它们是)。你会发现它们是使用 async/await
的好地方。特别是考虑到 UI 线程的同步上下文默认情况下将在同一线程上保持延续。当然,您可以通过使用 Task.Run
将 async/await
与 CPU 绑定操作一起使用。什么时候这是个好主意?啊,是的,当你想保持 UI 响应时。
我有以下代码:
static void Main(string[] args)
{
Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));
int count = 5;
do
{
Console.WriteLine(count.ToString());
Thread.Sleep(100);
count++;
} while (count < 20);
Console.ReadKey();
}
private static void LongProcess()
{
Console.WriteLine("Long Process 1");
Thread.Sleep(2000);
Console.WriteLine("Long Process 2");
}
private static void LongerProcess()
{
Console.WriteLine("Longer Process 1");
Thread.Sleep(3000);
Console.WriteLine("Longer Process 2");
}
private static async Task Run(Action action)
{
await Task.Run(action); //shouldn't this wait until the action is completed??
// how should I modify the code so that the program waits until action is done before returning?
}
对于 await Task.Run(action);
,我希望程序会等到 action
完成,然后再继续下一步。换句话说,我期待这样的输出:
Long Process 1
Long Process 2
Longer Process 1
Longer Process 2
5
6
7
8
...
19
然而,输出就像
Long Process 1
5
6
7
8
...
19
Long Process 2
Longer Process 1
Longer Process 2
问题:
- 为什么
await Task.Run
不等到action
完成? - 如何更改代码以提供我想要的输出?
使用await
不等待,这就是重点。如果要等待,请使用 Task.Wait
.
但是,async
方法的执行只有在等待的任务完成后才会继续执行(这是一个延续)。让我们看看您的 async
方法:
private static async Task Run(Action action)
{
await Task.Run(action);
// There is nothing here
}
任务完成后没有要执行的代码...好吧,async
方法returns一个任务完成时完成的任务。让我们看看您是否await
...
Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));
你不知道。你解雇了那个任务,然后忘了它。
我想这就是你想要的:
static async void Main(string[] args)
{
await Run(() => LongProcess());
await Run(() => LongerProcess());
int count = 5;
do
{
Console.WriteLine(count.ToString());
Thread.Sleep(100);
count++;
} while (count < 20);
Console.ReadKey();
}
注意:Async Main 是 C# 7.1 的一项功能。
此代码将 运行 调用 LongProcess
的任务,然后作为 运行 调用 LongerProcess
的任务的延续,然后作为延续其余部分代码。
为什么你想要那个而不是仅仅同步调用这些方法我无法理解。
顺便说一下,在 async
方法中,您可以使用 await Task.Delay(milliseconds)
而不是 Thread.Sleep(milliseconds)
。优点是线程不等待。 这就像在单个执行计时器上进行延续。
如果 async/await
只是延续,您可能想知道为什么人们要使用它们而不是 ContinueWith
。
让我给你几个理由:
- 带有
async/await
的代码更易于阅读。更少的嵌套内容使代码变得模糊。您可以独立于理解线程来理解代码的作用。 -
async/await
的代码更容易编写。你只是把它写得好像它们都是同步的,其中有一些async
和await
闪闪发光。您可以编写同步代码,然后担心如何使其并发。您最终也会写得更少,这意味着您的工作效率更高。 - 带有
async/await
的代码更聪明™。编译器将您的代码重写为连续状态机,允许您将await
放入语句中而无需任何代码体操™。这扩展到异常处理。你看,在你的 fire and forget 任务继续中,你没有处理异常。如果LongerProcess
抛出怎么办?好吧,使用async/await
,您只需将await
放在try ... catch
中,它就会做正确的事情™。
这就是很好的关注点分离。
您可能还想知道在什么情况下使用 async/await
而不是同步代码是个好主意。答案是它在处理 I/O 操作时大放异彩。与外部系统交互时,通常不会立即得到响应。例如,如果你想从磁盘读取或从网络下载。
事实上,如果您考虑将操作表单和处理其事件视为 I/O 绑定操作(因为,它们是)。你会发现它们是使用 async/await
的好地方。特别是考虑到 UI 线程的同步上下文默认情况下将在同一线程上保持延续。当然,您可以通过使用 Task.Run
将 async/await
与 CPU 绑定操作一起使用。什么时候这是个好主意?啊,是的,当你想保持 UI 响应时。