我正在學習異步/等待,並遇到須要同步調用異步方法的狀況。 我怎樣才能作到這一點? 安全
異步方法: app
public async Task<Customers> GetCustomers() { return await Service.GetCustomersAsync(); }
正經常使用法: 異步
public async void GetCustomers() { customerList = await GetCustomers(); }
我嘗試使用如下方法: async
Task<Customer> task = GetCustomers(); task.Wait() Task<Customer> task = GetCustomers(); task.RunSynchronously(); Task<Customer> task = GetCustomers(); while(task.Status != TaskStatus.RanToCompletion)
我也從這裏嘗試了一個建議,可是當調度程序處於掛起狀態時,它不起做用。 ide
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
的異常和堆棧跟蹤: 性能
System.InvalidOperationException 學習
消息 :在未綁定到委託的任務上,可能不會調用RunSynchronously。 this
InnerException :空 spa
資料來源 :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()
請注意-這種方法:
Task<Customer> task = GetCustomers(); task.Wait()
適用於WinRT。
讓我解釋:
private void TestMethod() { Task<Customer> task = GetCustomers(); // call async method as sync and get task as result task.Wait(); // wait executing the method var customer = task.Result; // get's result. Debug.WriteLine(customer.Name); //print customer name } public class Customer { public Customer() { new ManualResetEvent(false).WaitOne(TimeSpan.FromSeconds(5));//wait 5 second (long term operation) } public string Name { get; set; } } private Task<Customer> GetCustomers() { return Task.Run(() => new Customer { Name = "MyName" }); }
並且,這種方法僅適用於Windows Store解決方案!
注意:若是您在其餘異步方法中調用方法,則這種方法不是線程安全的(根據@Servy的註釋)
被告知這個答案是三歲。 我主要是基於.Net 4.0的經驗編寫的,不多基於4.5的經驗編寫的,尤爲是async-await
。 通常來講,這是一個很好的簡單解決方案,但有時會破壞事情。 請閱讀評論中的討論。
只需使用此:
// For Task<T>: will block until the task is completed... var result = task.Result; // For Task (not Task<T>): will block until the task is completed... task2.RunSynchronously();
請參閱: TaskAwaiter , Task.Result , Task.Run同步
用這個:
var x = (IAsyncResult)task; task.Start(); x.AsyncWaitHandle.WaitOne();
...或這個:
task.Start(); task.Wait();
在wp8上:
包裝:
Task GetCustomersSynchronously() { Task t = new Task(async () => { myCustomers = await GetCustomers(); } t.RunSynchronously(); }
稱它爲:
GetCustomersSynchronously();
在線程池上運行任務要簡單得多,而不是試圖欺騙調度程序使其同步運行。 這樣,您能夠肯定它不會死鎖。 因爲上下文切換,性能受到影響。
Task<MyResult> DoSomethingAsync() { ... } // Starts the asynchronous task on a thread-pool thread. // Returns a proxy to the original task. Task<MyResult> task = Task.Run(() => DoSomethingAsync()); // Will block until the task is completed... MyResult result = task.Result;
private int GetSync() { try { ManualResetEvent mre = new ManualResetEvent(false); int result = null; Parallel.Invoke(async () => { result = await SomeCalcAsync(5+5); mre.Set(); }); mre.WaitOne(); return result; } catch (Exception) { return null; } }