我将如何运行异步任务方法同步?
我正在学习 async/await,并遇到了需要同步调用异步方法的情况。我怎样才能做到这一点?
异步方法:
public async Task<Customers> GetCustomers()
{
return await Service.GetCustomersAsync();
}
正常用法:
public async void GetCustomers()
{
customerList = await GetCustomers();
}
我尝试使用以下方法:
Task<Customer> task = GetCustomers();
task.Wait()
Task<Customer> task = GetCustomers();
task.RunSynchronously();
Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)
我还尝试了 此处,但是当调度程序处于挂起状态时它不起作用。
public static void WaitWithPumping(this Task task)
{
if (task == null) throw new ArgumentNullException(“task”);
var nestedFrame = new DispatcherFrame();
task.ContinueWith(_ => nestedFrame.Continue = false);
Dispatcher.PushFrame(nestedFrame);
task.Wait();
}
以下是调用 RunSynchronously 的异常和堆栈跟踪:
系统.InvalidOperationException
消息:无法对未绑定到委托的任务调用 RunSynchronously。
内部异常:空
来源:mscorlib
StackTrace:
at System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler scheduler)
at System.Threading.Tasks.Task.RunSynchronously()
at MyApplication.CustomControls.Controls.MyCustomControl.CreateAvailablePanelList() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 638
at MyApplication.CustomControls.Controls.MyCustomControl.get_AvailablePanels() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 233
at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>b__36(DesktopPanel panel) in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 597
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>d__3b.MoveNext() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 625
at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass7.<TrySetContinuationForAwait>b__1(Object state)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at MyApplication.App.Main() in C:\Documents and Settings\...\MyApplication\obj\Debug\App.g.cs:line 50
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(23)
这是我发现的一种适用于所有情况(包括暂停的调度员)的解决方法。这不是我的代码,我仍在努力完全理解它,但它确实有效。
可以使用以下方式调用它:
customerList = AsyncHelpers.RunSync
>(() => GetCustomers());
代码来自 此处
Here's a workaround I found that works for all cases (including suspended dispatchers). It's not my code and I'm still working to fully understand it, but it does work.
It can be called using:
customerList = AsyncHelpers.RunSync<List<Customer>>(() => GetCustomers());
Code is from here
请注意这个答案已有三年了。我主要根据 .Net 4.0 的经验编写它,而很少根据 4.5 尤其是
async-await
的经验来编写它。一般来说,这是一个很好的简单解决方案,但有时会破坏一些东西。请阅读评论中的讨论。
.Net 4.5
只需使用这个:
请参阅:
TaskAwaiter,
任务.Result,
Task.RunSynchronously
.Net 4.0
使用此:
...或此:
Be advised this answer is three years old. I wrote it based mostly on a experience with .Net 4.0, and very little with 4.5 especially with
async-await
.Generally speaking it's a nice simple solution, but it sometimes breaks things. Please read the discussion in the comments.
.Net 4.5
Just use this:
See:
TaskAwaiter,
Task.Result,
Task.RunSynchronously
.Net 4.0
Use this:
...or this:
令人惊讶的是没有人提到这一点:
不像这里的其他一些方法那么漂亮,但它具有以下优点:
Wait
)AggregateException
(如Result
)Task
和Task
(try it out yourself!)Also, since
GetAwaiter
是鸭子类型的,这应该适用于从异步方法返回的任何对象(例如ConfiguredAwaitable
或YieldAwaitable
),而不仅仅是任务。编辑:请注意,这种方法(或使用
.Result
)可能会出现死锁,除非您确保添加.ConfigureAwait(false)
每次您等待时,对于可以从BlahAsync()
访问的所有异步方法(不仅仅是它直接调用的方法)。 说明。如果你懒得到处添加
.ConfigureAwait(false)
,并且你不关心性能,你也可以这样做Surprised no one mentioned this:
Not as pretty as some of the other methods here, but it has the following benefits:
Wait
)AggregateException
(likeResult
)Task
andTask<T>
(try it out yourself!)Also, since
GetAwaiter
is duck-typed, this should work for any object that is returned from an async method (likeConfiguredAwaitable
orYieldAwaitable
), not just Tasks.edit: Please note that it's possible for this approach (or using
.Result
) to deadlock, unless you make sure to add.ConfigureAwait(false)
every time you await, for all async methods that can possibly be reached fromBlahAsync()
(not just ones it calls directly). Explanation.If you're too lazy to add
.ConfigureAwait(false)
everywhere, and you don't care about performance you can alternatively do在线程池上运行任务要简单得多,而不是试图欺骗调度程序同步运行它。这样你就可以确保它不会陷入僵局。由于上下文切换,性能会受到影响。
It's much simpler to run the task on the thread pool, rather than trying to trick the scheduler to run it synchronously. That way you can be sure that it won't deadlock. Performance is affected because of the context switch.
最好的答案是你不需要,具体细节取决于“情况”是什么。
它是属性获取器/设置器吗?在大多数情况下,拥有异步方法比“异步属性”更好。 (有关详细信息,请参阅我关于异步属性的博客文章)。
这是一个 MVVM 应用程序并且您想要进行异步数据绑定吗?然后使用类似于我的
NotifyTask
的内容,如我的 有关异步数据绑定的 MSDN 文章。它是一个构造函数吗?那么您可能需要考虑异步工厂方法。 (有关详细信息,请参阅我的关于异步构造函数的博客文章)。
几乎总是有比异步同步更好的答案。
如果您的情况不可能(并且您通过在描述情况中提出问题来了解这一点),那么我建议仅使用同步代码。始终异步是最好的;一路同步是第二好的。不建议使用异步同步。
然而,在少数情况下,异步同步是必要的。具体来说,您受到调用代码的限制,因此您必须要同步(并且绝对没有办法重新思考或重新构造代码以允许异步),和您必须调用异步代码。这是一种非常罕见的情况,但确实时有发生。
在这种情况下,您需要使用我关于 brownfield 的文章中描述的黑客之一
异步
开发,具体来说:GetAwaiter().GetResult()
)。请注意,这可能会导致死锁(正如我在我的博客上描述)。Task.Run(..).GetAwaiter().GetResult()
)。请注意,只有当异步代码可以在线程池线程上运行(即不依赖于 UI 或 ASP.NET 上下文)时,这才有效。嵌套消息循环是所有黑客攻击中最危险的,因为它会导致重入 。重新进入是非常难以推理的,并且(IMO)是 Windows 上大多数应用程序错误的原因。特别是,如果您位于 UI 线程上并且阻塞工作队列(等待异步工作完成),那么 CLR 实际上会为您执行一些消息泵操作 - 它实际上会处理一些 Win32 消息从您的代码中。哦,你不知道哪些消息 - 当 Chris Brumme 说“如果能准确地知道会抽吸什么不是很好吗?不幸的是,抽吸是一门超出凡人理解范围的黑术。”,然后我们真的没有希望知道。
因此,当您在 UI 线程上像这样阻塞时,您就是在自找麻烦。同一篇文章中的另一个 cbrumme 引用:“公司内部或外部的客户有时会发现我们在 STA [UI 线程] 上的托管阻塞期间泵送消息。这是一个合理的担忧,因为他们知道这非常困难编写面对重入时稳健的代码。”
是的。 非常很难编写在重入面前保持健壮的代码。嵌套消息循环迫使您编写面对重入时稳健的代码。这就是为什么这个问题被接受的(也是投票最多的)答案极其危险实践。
如果您完全没有其他选择 - 您无法重新设计代码,无法将其重组为异步 - 您被迫通过不可更改的调用代码来同步 - 您无法将下游代码更改为同步- 你不能阻塞 - 你不能在单独的线程上运行异步代码 - 然后并且只有这样你才应该考虑拥抱重入。
如果您确实发现自己处于这个角落,我建议使用类似
Dispatcher.PushFrame
对于 WPF 应用程序,对于 WinForm 应用程序使用Application.DoEvents
循环,对于一般情况,我自己的AsyncContext.Run
。The best answer is you don't, with the details dependent on what the "situation" is.
Is it a property getter/setter? In most cases, it's better to have asynchronous methods than "asynchronous properties". (For more info, see my blog post on asynchronous properties).
Is this an MVVM app and you want to do asynchronous data binding? Then use something like my
NotifyTask
, as described in my MSDN article on asynchronous data binding.Is it a constructor? Then you probably want to consider an asynchronous factory method. (For more info, see my blog post on asynchronous constructors).
There's almost always a better answer than to do sync-over-async.
If it's not possible for your situation (and you know this by asking a question here describing the situation), then I'd recommend just using synchronous code. Async all the way is best; sync all the way is second-best. Sync-over-async is not recommended.
However, there are a handful of situations where sync-over-async is necessary. Specifically, you are constrained by the calling code so that you have to be sync (and have absolutely no way to re-think or re-structure your code to allow asynchrony), and you have to call async code. This is a very rare situation, but it does come up from time to time.
In that case, you would need to use one of the hacks described in my article on brownfield
async
development, specifically:GetAwaiter().GetResult()
). Note that this can cause deadlocks (as I describe on my blog).Task.Run(..).GetAwaiter().GetResult()
). Note that this will only work if the asynchronous code can be run on a thread pool thread (i.e., is not dependent on a UI or ASP.NET context).Nested message loops are the most dangerous of all the hacks, because it causes re-entrancy. Re-entrancy is extremely tricky to reason about, and (IMO) is the cause of most application bugs on Windows. In particular, if you're on the UI thread and you block on a work queue (waiting for the async work to complete), then the CLR actually does some message pumping for you - it'll actually handle some Win32 messages from within your code. Oh, and you have no idea which messages - when Chris Brumme says "Wouldn’t it be great to know exactly what will get pumped? Unfortunately, pumping is a black art which is beyond mortal comprehension.", then we really have no hope of knowing.
So, when you block like this on a UI thread, you're asking for trouble. Another cbrumme quote from the same article: "From time to time, customers inside or outside the company discover that we are pumping messages during managed blocking on an STA [UI thread]. This is a legitimate concern, because they know that it’s very hard to write code that’s robust in the face of reentrancy."
Yes, it is. Very hard to write code that's robust in the face of reentrancy. And nested message loops force you to write code that's robust in the face of reentrancy. This is why the accepted (and most-upvoted) answer for this question is extremely dangerous in practice.
If you are completely out of all other options - you can't redesign your code, you can't restructure it to be async - you are forced by unchangeable calling code to be sync - you can't change the downstream code to be sync - you can't block - you can't run the async code on a separate thread - then and only then should you consider embracing reentrancy.
If you do find yourself in this corner, I would recommend using something like
Dispatcher.PushFrame
for WPF apps, looping withApplication.DoEvents
for WinForm apps, and for the general case, my ownAsyncContext.Run
.如果我正确地阅读了您的问题 - 想要同步调用异步方法的代码正在挂起的调度程序线程上执行。并且您希望实际上同步阻止该线程,直到异步方法完成。
C# 5 中的异步方法是通过在底层有效地将方法分成多个部分,并返回一个可以跟踪整个 shabang 整体完成情况的
Task
来提供支持的。但是,切碎的方法的执行方式可能取决于传递给await
运算符的表达式的类型。大多数时候,您将在
Task
类型的表达式上使用await
。任务对await
模式的实现是“智能”的,因为它遵循SynchronizationContext
,这基本上会导致发生以下情况:await< /code> 位于 Dispatcher 或 WinForms 消息循环线程上,它确保异步方法的块作为消息队列处理的一部分发生。
这就是为什么您可能会遇到问题 - 异步方法实现正在尝试在调度程序上运行其余部分 - 即使它已挂起。
....备份! ....
我必须问一个问题,为什么 你试图同步阻塞异步方法?这样做会违背为什么要异步调用该方法的目的。一般来说,当您开始在 Dispatcher 或 UI 方法上使用
await
时,您将希望将整个 UI 流程设为异步。例如,如果您的调用堆栈如下所示:WebRequest.GetResponse()
YourCode.HelperMethod()
YourCode .AnotherMethod()
YourCode.EventHandlerMethod()
[UI 代码].Plumbing()
-WPF
或WinForms< /code> 代码
WPF
或WinForms
消息循环然后,一旦将代码转换为使用异步,您通常会最终为
WebRequest.GetResponseAsync()
YourCode.HelperMethodAsync()
YourCode.AnotherMethodAsync()
[UI 代码].Plumbing()
-WPF
或WinForms
代码WPF
或WinForms
消息循环实际应答
上面的 AsyncHelpers 类实际上可以工作,因为它行为类似于嵌套消息循环,但它将自己的并行机制安装到 Dispatcher,而不是尝试在 Dispatcher 本身上执行。这是解决您的问题的一种方法。
另一种解决方法是在线程池线程上执行异步方法,然后等待它完成。这样做很简单 - 您可以使用以下代码片段来完成:
最终的 API 将是 Task.Run(...),但使用 CTP,您将需要 Ex 后缀 (此处有说明)。
If I am reading your question right - the code that wants the synchronous call to an async method is executing on a suspended dispatcher thread. And you want to actually synchronously block that thread until the async method is completed.
Async methods in C# 5 are powered by effectively chopping the method into pieces under the hood, and returning a
Task
that can track the overall completion of the whole shabang. However, how the chopped up methods execute can depend on the type of the expression passed to theawait
operator.Most of the time, you'll be using
await
on an expression of typeTask
. Task's implementation of theawait
pattern is "smart" in that it defers to theSynchronizationContext
, which basically causes the following to happen:await
is on a Dispatcher or WinForms message loop thread, it ensures that the chunks of the async method occurs as part of the processing of the message queue.await
is on a thread pool thread, then the remaining chunks of the async method occur anywhere on the thread pool.That's why you're probably running into problems - the async method implementation is trying to run the rest on the Dispatcher - even though it's suspended.
.... backing up! ....
I have to ask the question, why are you trying to synchronously block on an async method? Doing so would defeat the purpose on why the method wanted to be called asynchronously. In general, when you start using
await
on a Dispatcher or UI method, you will want to turn your entire UI flow async. For example, if your callstack was something like the following:WebRequest.GetResponse()
YourCode.HelperMethod()
YourCode.AnotherMethod()
YourCode.EventHandlerMethod()
[UI Code].Plumbing()
-WPF
orWinForms
CodeWPF
orWinForms
Message LoopThen once the code has been transformed to use async, you'll typically end up with
WebRequest.GetResponseAsync()
YourCode.HelperMethodAsync()
YourCode.AnotherMethodAsync()
YourCode.EventHandlerMethodAsync()
[UI Code].Plumbing()
-WPF
orWinForms
CodeWPF
orWinForms
Message LoopActually Answering
The AsyncHelpers class above actually works because it behaves like a nested message loop, but it installs its own parallel mechanic to the Dispatcher rather than trying to execute on the Dispatcher itself. That's one workaround for your problem.
Another workaround is to execute your async method on a threadpool thread, and then wait for it to complete. Doing so is easy - you can do it with the following snippet:
The final API will be Task.Run(...), but with the CTP you'll need the Ex suffixes (explanation here).
这对我来说效果很好
This is working well for me
在 .Net 4.6 中测试。也可以避免死锁。
对于返回
Task
的异步方法。对于返回
Task
Edit 的异步方法:
如果调用者运行在线程池线程中(或者调用者也在任务中),仍然可能会导致在某些情况下陷入僵局。
Tested in .Net 4.6. It can also avoid deadlock.
For async method returning
Task
.For async method returning
Task<T>
Edit:
If the caller is running in the thread pool thread (or the caller is also in a task), it may still cause a deadlock in some situation.
我在 Microsoft.AspNet.Identity.Core 组件中找到了这段代码,它可以工作。
I found this code at Microsoft.AspNet.Identity.Core component, and it works.
我遇到过几次,主要是在单元测试或 Windows 服务开发中。目前我一直在使用这个功能:
它简单、容易,而且我没有遇到任何问题。
I've faced it a few times, mostly in unit testing or in a windows service development. Currently I always use this feature:
It's simple, easy and I had no problems.
我发现同步运行任务且不阻塞 UI 线程的最简单方法是使用 RunSynchronously() ,例如:
在我的例子中,我有一个在发生某些事情时触发的事件。我不知道这样的事情会发生多少次。因此,我在事件中使用上面的代码,因此每当它触发时,它都会创建一个任务。任务是同步执行的,这对我来说非常有用。我只是很惊讶,考虑到它是如此简单,我花了这么长时间才发现它。通常,建议要复杂得多并且容易出错。这就是它的简单和干净。
The simplest way I have found to run task synchronously and without blocking UI thread is to use RunSynchronously() like:
In my case, I have an event that fires when something occurs. I dont know how many times it will occur. So, I use code above in my event, so whenever it fires, it creates a task. Tasks are executed synchronously and it works great for me. I was just surprised that it took me so long to find out of this considering how simple it is. Usually, recommendations are much more complex and error prone. This was it is simple and clean.
请注意 - 此方法:
适用于 WinRT。
让我解释一下:
此外,这种方法仅适用于 Windows 应用商店解决方案!
注意:如果您在其他异步方法内部调用您的方法,则这种方式不是线程安全的(根据@Servy的注释)
Just a little note - this approach:
works for WinRT.
Let me explain:
Moreover this approach works for Windows Store solutions only!
Note: This way isn't thread safe if you call your method inside of other async method (according to comments of @Servy)
注意:我认为,如果操作是异步的,最好的做法是不建议更改操作的性质,最好按原样处理(始终异步)。通过这种方式,您可以获得其他好处,例如并行处理/多线程等。
看到其他答案没有使用这种方法,我也想将其发布在这里:
NOTE: I think as best practice is not recommended to change the nature of the action if it is asynchronous the best thing is handling as it is (async all the way). In that way you can get other benefits like parallel processing / multi-threading, etc.
Seeing the other answers did not use this approach, I want to post it here as well:
在您的代码中,您的第一个等待任务执行,但您尚未启动它,因此它会无限期地等待。试试这个:
编辑:
您说您遇到了例外情况。请发布更多详细信息,包括堆栈跟踪。
单声道 包含以下测试用例:
检查这是否适合您。如果没有,尽管可能性很小,您可能会使用一些奇怪的异步 CTP 版本。如果它确实有效,您可能需要检查编译器到底生成了什么以及任务实例化与此示例有何不同。
编辑#2:
我向 Reflector 核实,当
m_action
为null
时,会发生您所描述的异常。这有点奇怪,但我不是异步 CTP 方面的专家。正如我所说,您应该反编译代码并查看Task
是如何实例化的,以及它的m_action
为何为null
。In your code, your first wait for task to execute but you haven't started it so it waits indefinitely. Try this:
Edit:
You say that you get an exception. Please post more details, including stack trace.
Mono contains the following test case:
Check if this works for you. If it does not, though very unlikely, you might have some odd build of Async CTP. If it does work, you might want to examine what exactly the compiler generates and how
Task
instantiation is different from this sample.Edit #2:
I checked with Reflector that the exception you described occurs when
m_action
isnull
. This is kinda odd, but I'm no expert on Async CTP. As I said, you should decompile your code and see how exactlyTask
is being instantiated any how come itsm_action
isnull
.为什么不创建一个像这样的调用:
这不是异步的。
Why not create a call like:
that isn't async.
此答案是为使用 WPF for .NET 4.5 的任何人设计的。
如果您尝试在 GUI 线程上执行
Task.Run()
,并且您没有async<,则
task.Wait()
将无限期挂起。函数定义中的 /code> 关键字。此扩展方法通过检查我们是否位于 GUI 线程上来解决问题,如果是,则在 WPF 调度程序线程上运行任务。
在不可避免的情况下,例如 MVVM 属性或对不使用 async/await 的其他 API 的依赖,此类可以充当 async/await 世界和非 async/await 世界之间的粘合剂。
This answer is designed for anyone who is using WPF for .NET 4.5.
If you attempt to execute
Task.Run()
on the GUI thread, thentask.Wait()
will hang indefinitely, if you do not have theasync
keyword in your function definition.This extension method solves the problem by checking to see if we are on the GUI thread, and if so, running the task on the WPF dispatcher thread.
This class can act as the glue between the async/await world and the non-async/await world, in situations where it is unavoidable, such as MVVM properties or dependencies on other APIs that do not use async/await.
正如许多人在评论中所说,简单地调用
.Result;
或.Wait()
就会带来死锁的风险。由于我们大多数人都喜欢 oneliner,因此您可以将它们用于.Net 4.5<
通过异步方法获取值:
同步调用异步方法
由于使用
Task 不会出现死锁问题.运行
。来源:
https://stackoverflow.com/a/32429753/3850405
Simply calling
.Result;
or.Wait()
is a risk for deadlocks as many have said in comments. Since most of us like oneliners you can use these for.Net 4.5<
Acquiring a value via an async method:
Syncronously calling an async method
No deadlock issues will occur due to the use of
Task.Run
.Source:
https://stackoverflow.com/a/32429753/3850405
使用下面的代码片段
use below code snip
这对我有用
This is works for me
我认为下面的辅助方法也可以解决这个问题。
可以通过以下方式使用:
I think the following helper method could also solve the problem.
Can be used the following way:
异步方法:
这似乎对我有用:
Async method:
This seems to work for me:
我发现 SpinWait 对此非常有效。
上述方法不需要使用.Result或.Wait()。它还允许您指定超时,以便在任务永远无法完成的情况下您不会永远陷入困境。
I have found that SpinWait works pretty well for this.
The above approach doesn't need to use .Result or .Wait(). It also lets you specify a timeout so that you're not stuck forever in case the task never completes.