C# 在一个方法中调用同步和异步方法(api/UI)的正确方法是什么
在下面的示例中,我在同步方法UI中调用异步方法。 在异步方法中,我调用了另一个异步方法api调用,但我也调用了其他同步方法,例如update combobox。现在我使用InvokeMethodInvoker。。。对于每个同步方法调用。这是正确的方法吗?能做得更好吗?不,我还必须考虑使用InvokeMethodInvoker。。。在异步方法中调用同步方法时C# 在一个方法中调用同步和异步方法(api/UI)的正确方法是什么,c#,asynchronous,C#,Asynchronous,在下面的示例中,我在同步方法UI中调用异步方法。 在异步方法中,我调用了另一个异步方法api调用,但我也调用了其他同步方法,例如update combobox。现在我使用InvokeMethodInvoker。。。对于每个同步方法调用。这是正确的方法吗?能做得更好吗?不,我还必须考虑使用InvokeMethodInvoker。。。在异步方法中调用同步方法时 private void control_SelectionValueChanged(Object sender, EventArgs e)
private void control_SelectionValueChanged(Object sender, EventArgs e)
{
Task task = Task.Run(async () => await SomeMethodAsync());
}
private async Task SomeMethodAsync()
{
Invoke((MethodInvoker)(() => SomeMethodA))
bool variable = await SomeOtherMethodAsync()
if ( variable ) Invoke((MethodInvoker)(() => SomeMethodB))
Invoke((MethodInvoker)(() => SomeMethodC))
}
我们来分析一下这里发生的事情 当您的控件\u SelectionValueChanged处理程序启动时,我假设我们正在UI线程上运行。然后你: 通过Task.Run在线程池线程上启动SomeMethodAsync。这不会阻止UI线程。 一旦线程池线程开始执行SomeMethodAsync,您就要求运行时通过调用Control.Invoke将您封送回UI线程。当SomeMethodA在UI线程上执行时,您同时也在阻塞线程池线程。 然后解除对线程池线程的阻止,并要求它执行其他异步方法。除非SomeOtherMethodAsync中有什么奇怪的东西,例如另一个控件。Invoke调用,否则整个操作都将远离UI线程 等待之后,返回线程池线程-这可能是等待之前的相同线程池线程,也可能是不同的线程池线程-这取决于TaskScheduler。 如果variable为true,则在UI线程上执行SomeMethodB,同时再次阻塞线程池线程。 最后,在UI线程上执行SomeMethodC,同时最后一次阻塞线程池线程。 如您所见,大部分时间SomeMethodAsync都在执行,但等待SomeOtherMethodAsync的时间除外,以及控件之间的短暂间隔。调用您仍在使用UI线程,但您也在阻塞线程池线程。因此,您现在占用了两个线程,其中大部分只有一个线程在做有用的工作,而另一个线程只是坐在那里等待 除了读起来非常可怕之外,这也是非常低效的 考虑以下重写:
private async void control_SelectionValueChanged(Object sender, EventArgs e)
{
try
{
await SomeMethodAsync();
}
catch (Exception ex)
{
// We're an async void, so don't forget to handle exceptions.
MessageBox.Show(ex.Message);
}
}
private async Task SomeMethodAsync()
{
// We're on the UI thread, and we will stay on the UI
// thread *at least* until we hit the `await` keyword.
SomeMethodA();
// We're still on the UI thread, but if `SomeOtherMethodAsync`
// is a genuinely asynchronous method, we will go asynchronous
// as soon as `SomeOtherMethodAsync` hits the its `await` on a
// `Task` that does not transition to `Completed` state immediately.
bool variable = await SomeOtherMethodAsync();
// If you need stronger guarantees that `SomeOtherMethodAsync`
// will stay off the UI thread, you can wrap it in Task.Run, so
// that its synchronous portions (if any) run on a thread pool
// thread (as opposed to the UI thread).
// bool variable = await Task.Run(() => SomeOtherMethodAsync());
// We're back on the UI thread for the remainder of this method.
if ( variable ) SomeMethodB();
// Still on the UI thread.
SomeMethodC();
}
上面的内容很相似,尽管在行为方面并不完全相同,但阅读起来不是更容易吗?让我们来分析一下这里发生的事情 当您的控件\u SelectionValueChanged处理程序启动时,我假设我们正在UI线程上运行。然后你: 通过Task.Run在线程池线程上启动SomeMethodAsync。这不会阻止UI线程。 一旦线程池线程开始执行SomeMethodAsync,您就要求运行时通过调用Control.Invoke将您封送回UI线程。当SomeMethodA在UI线程上执行时,您同时也在阻塞线程池线程。 然后解除对线程池线程的阻止,并要求它执行其他异步方法。除非SomeOtherMethodAsync中有什么奇怪的东西,例如另一个控件。Invoke调用,否则整个操作都将远离UI线程 等待之后,返回线程池线程-这可能是等待之前的相同线程池线程,也可能是不同的线程池线程-这取决于TaskScheduler。 如果variable为true,则在UI线程上执行SomeMethodB,同时再次阻塞线程池线程。 最后,在UI线程上执行SomeMethodC,同时最后一次阻塞线程池线程。 如您所见,大部分时间SomeMethodAsync都在执行,但等待SomeOtherMethodAsync的时间除外,以及控件之间的短暂间隔。调用您仍在使用UI线程,但您也在阻塞线程池线程。因此,您现在占用了两个线程,其中大部分只有一个线程在做有用的工作,而另一个线程只是坐在那里等待 除了读起来非常可怕之外,这也是非常低效的 考虑以下重写:
private async void control_SelectionValueChanged(Object sender, EventArgs e)
{
try
{
await SomeMethodAsync();
}
catch (Exception ex)
{
// We're an async void, so don't forget to handle exceptions.
MessageBox.Show(ex.Message);
}
}
private async Task SomeMethodAsync()
{
// We're on the UI thread, and we will stay on the UI
// thread *at least* until we hit the `await` keyword.
SomeMethodA();
// We're still on the UI thread, but if `SomeOtherMethodAsync`
// is a genuinely asynchronous method, we will go asynchronous
// as soon as `SomeOtherMethodAsync` hits the its `await` on a
// `Task` that does not transition to `Completed` state immediately.
bool variable = await SomeOtherMethodAsync();
// If you need stronger guarantees that `SomeOtherMethodAsync`
// will stay off the UI thread, you can wrap it in Task.Run, so
// that its synchronous portions (if any) run on a thread pool
// thread (as opposed to the UI thread).
// bool variable = await Task.Run(() => SomeOtherMethodAsync());
// We're back on the UI thread for the remainder of this method.
if ( variable ) SomeMethodB();
// Still on the UI thread.
SomeMethodC();
}
上面的内容很相似,尽管在行为方面并不完全相同,但阅读起来不是更容易吗?我建议不要将它们混合在一起。但是,您处于事件处理程序中这一事实允许在规则中出现异常,您可以在其中使用async void
我建议不要把它们混在一起。但是,您处于事件处理程序中这一事实允许在规则中出现异常,您可以在其中使用async void
非异步方法中的Task Task=SomeMethodAsync不是更有意义吗。MethodInvoker代码的逻辑是什么?为什么它更有意义?调用调用的方法是属于UI线程的同步方法。SomeOtherMethodAsync是一个api调用async。这一行对我来说毫无意义。您创建一个任务只是为了等待另一个任务。为什么不直接返回SomeMethodAsync的第一个任务结果呢?非异步方法中的task task=SomeMethodAsync不是更有意义吗。MethodInvoker代码的逻辑是什么?为什么它更有意义?调用调用的方法是属于
到UI线程。SomeOtherMethodAsync是一个api调用async。这一行对我来说毫无意义。您创建一个任务只是为了等待另一个任务。为什么不直接返回SomeMethodAsync的第一个任务结果呢。