我将如何运行的异步任务< T>方法同步? [英] How would I run an async Task<T> method synchronously?

查看:142
本文介绍了我将如何运行的异步任务< T>方法同步?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我学习异步/在等待着,碰到了一个情况,我需要调用同步异步方法。我该怎么做?

异步方法:

 公共异步任务<客户和GT; GetCustomers的()
{
    返回等待Service.GetCustomersAsync();
}

正常使用的情况:

 公共异步无效GetCustomers的()
{
    customerList = GetCustomers的等待();
}

我用下面的尝试:

 任务<客户>任务= GetCustomers的();
task.Wait()任务<客户>任务= GetCustomers的();
task.RunSynchronously();任务<客户>任务= GetCustomers的();
而(task.Status!= TaskStatus.RanToCompletion)

我也尝试从一个建议<一href=\"http://social.msdn.microsoft.com/Forums/en/async/thread/163ef755-ff7b-4ea5-b226-bbe8ef5f4796\">here,然而,当调度员处于暂停状态下,它不工作。

 公共静态无效WaitWithPumping(该任务的任务)
{
        如果(任务== NULL)抛出新的ArgumentNullException(任务);
        VAR nestedFrame =新DispatcherFrame();
        task.ContinueWith(_ =&GT; nestedFrame.Continue = FALSE);
        Dispatcher.PushFrame(nestedFrame);
        task.Wait();
}

下面是调用异常和堆栈跟踪 RunSynchronously


  

System.InvalidOperationException


  
  

消息:RunSynchronously可能不会被要求绑定到委托的任务


  
  

的InnerException :空


  
  

源代码:mscorlib程序


  
  

堆栈跟踪


 在System.Threading.Tasks.Task.InternalRunSynchronously(的TaskScheduler调度)
   在System.Threading.Tasks.Task.RunSynchronously()
   在MyApplication.CustomControls.Controls.MyCustomControl.CreateAvailablePanelList()在C:\\的Documents and Settings \\ ... \\ MyApplication.CustomControls \\控件\\ MyCustomControl.xaml.cs:638线
   在MyApplication.CustomControls.Controls.MyCustomControl.get_AvailablePanels()在C:\\的Documents and Settings \\ ... \\ MyApplication.CustomControls \\控件\\ MyCustomControl.xaml.cs:233线
   在MyApplication.CustomControls.Controls.MyCustomControl&LT; CreateOpenPanelList&GT; b__36(DesktopPanel面板)在C:\\的Documents and Settings \\ ... \\ MyApplication.CustomControls \\控件\\ MyCustomControl.xaml.cs:597线
   在System.Collections.Generic.List`1.ForEach(Action`1动作)
   在MyApplication.CustomControls.Controls.MyCustomControl&LT; CreateOpenPanelList&GT; d__3b.MoveNext()在C:\\的Documents and Settings \\ ... \\ MyApplication.CustomControls \\控件\\ MyCustomControl.xaml.cs:625线
   在System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass7.<TrySetContinuationForAwait>b__1(Object州)
   在System.Windows.Threading.ExceptionWrapper.InternalRealCall(代表回调,对象指定参数时,的Int32 numArgs)
   在MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(对象源,委托方法,对象指定参数时,的Int32 numArgs,代表catchHandler)
   在System.Windows.Threading.DispatcherOperation.InvokeImpl()
   在System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(对象状态)
   在System.Threading.ExecutionContext.runTry code(用户数据对象)
   在System.Runtime.CompilerServices.RuntimeHelpers.Execute codeWithGuaranteedCleanup(试行code code,清理code撤销code,对象用户数据)
   在System.Threading.ExecutionContext.RunInternal(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态)
   在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态,布尔ignoreSyncCtx)
   在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态)
   在System.Windows.Threading.DispatcherOperation.Invoke()
   在System.Windows.Threading.Dispatcher.ProcessQueue()
   在System.Windows.Threading.Dispatcher.WndProcHook(IntPtr的HWND,味精的Int32,IntPtr的的wParam,lParam中的IntPtr,布尔和放大器;处理)
   在MS.Win32.HwndWrapper.WndProc(IntPtr的HWND,味精的Int32,IntPtr的的wParam,lParam中的IntPtr,布尔和放大器;处理)
   在MS.Win32.HwndSubclass.DispatcherCallbackOperation(对象o)
   在System.Windows.Threading.ExceptionWrapper.InternalRealCall(代表回调,对象指定参数时,的Int32 numArgs)
   在MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(对象源,委托方法,对象指定参数时,的Int32 numArgs,代表catchHandler)
   在System.Windows.Threading.Dispatcher.InvokeImpl(优先级的DispatcherPriority,时间跨度超时,代表法,对象指定参数时,的Int32 numArgs)
   在MS.Win32.HwndSubclass.SubclassWndProc(IntPtr的HWND,味精的Int32,IntPtr的的wParam,lParam中的IntPtr)
   在MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG&安培; MSG)
   在System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame帧)
   在System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame帧)
   在System.Windows.Threading.Dispatcher.Run()
   在System.Windows.Application.RunDispatcher(对象忽略)
   在System.Windows.Application.RunInternal(窗窗)
   在System.Windows.Application.Run(窗窗)
   在System.Windows.Application.Run()
   在MyApplication.App.Main()在C:\\的Documents and Settings \\ ... \\ MyApplication的\\ OBJ \\调试\\ App.g.cs:行50
   在System.AppDomain._nExecuteAssembly(RuntimeAssembly组装,字串[] args)
   在System.AppDomain.ExecuteAssembly(字符串assemblyFile,证据assemblySecurity,字串[] args)
   在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)
   在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态,布尔ignoreSyncCtx)
   在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态)
   在System.Threading.ThreadHelper.ThreadStart()


解决方案

下面是一个解决办法,我发现,对所有案件(包括暂停的调度员)的作品。这不是我的code和我还在充分了解它,但它确实工作。

可以使用被称为:

customerList = AsyncHelpers.RunSync&LT;名单,LT;客户&GT;&GT;(()=&GT; GetCustomers的());

code是<一个href=\"http://social.msdn.microsoft.com/Forums/en/async/thread/163ef755-ff7b-4ea5-b226-bbe8ef5f4796\">here

 公共静态类AsyncHelpers
{
    ///&LT;总结&gt;
    ///执行是一个异步任务&LT; T&GT;其中有一个void返回值同步方法
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =任务&GT;任务&LT; T&GT;方法来执行&LT; /参数&GT;
    公共静态无效RunSync(Func键&LT;任务&GT;任务)
    {
        VAR oldContext = SynchronizationContext.Current;
        VAR同步=新ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(同步);
        synch.Post(异步_ =&GT;
        {
            尝试
            {
                等待任务();
            }
            赶上(例外五)
            {
                synch.InnerException = E;
                扔;
            }
            最后
            {
                synch.EndMessageLoop();
            }
        }, 空值);
        synch.BeginMessageLoop();        SynchronizationContext.SetSynchronizationContext(oldContext);
    }    ///&LT;总结&gt;
    ///执行是一个异步任务&LT; T&GT;它具有同步一件T返回类型的方法
    ///&LT; /总结&gt;
    ///&LT; typeparam NAME =T&gt;返回类型&lt; / typeparam&GT;
    ///&LT; PARAM NAME =任务&GT;任务&LT; T&GT;方法来执行&LT; /参数&GT;
    ///&LT;&回报GT;&LT; /回报&GT;
    公共静态ŧRunSync&LT; T&GT;(Func键&LT;任务&LT; T&GT;&GT;任务)
    {
        VAR oldContext = SynchronizationContext.Current;
        VAR同步=新ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(同步);
        ŧRET =默认(T);
        synch.Post(异步_ =&GT;
        {
            尝试
            {
                RET =等待任务();
            }
            赶上(例外五)
            {
                synch.InnerException = E;
                扔;
            }
            最后
            {
                synch.EndMessageLoop();
            }
        }, 空值);
        synch.BeginMessageLoop();
        SynchronizationContext.SetSynchronizationContext(oldContext);
        返回RET;
    }    私有类ExclusiveSynchronizationContext:的SynchronizationContext
    {
        私人BOOL完成的;
        公共异常的InnerException {搞定;组; }
        只读的AutoResetEvent workItemsWaiting =新的AutoResetEvent(假);
        只读队列&LT元组LT; SendOrPostCallback,对象&gt;&GT;项目=
            新的问答LT元组LT; SendOrPostCallback,对象&gt;&GT;();        公共覆盖无效发送(SendOrPostCallback D,对象状态)
        {
            抛出新NotSupportedException异常(我们不能送我们到同一个线程);
        }        公共覆盖无效后(SendOrPostCallback D,对象状态)
        {
            锁定(项目)
            {
                items.Enqueue(Tuple.Create(D,状态));
            }
            workItemsWaiting.Set();
        }        公共无效EndMessageLoop()
        {
            帖子(_ =&GT;完成= TRUE,NULL);
        }        公共无效BeginMessageLoop()
        {
            而(!完成)
            {
                元组LT; SendOrPostCallback,对象&gt;任务= NULL;
                锁定(项目)
                {
                    如果(items.Count大于0)
                    {
                        任务= items.Dequeue();
                    }
                }
                如果(任务!= NULL)
                {
                    task.Item1(task.Item2);
                    如果(的InnerException!= NULL)//该方法引发了exeption
                    {
                        抛出新AggregateException(AsyncHelpers.Run方法引发了异常。的InnerException);
                    }
                }
                其他
                {
                    workItemsWaiting.WaitOne();
                }
            }
        }        公众覆盖SynchronizationContext的CreateCopy()
        {
            返回此;
        }
    }
}

I'm learning about async/await, and ran into a situation where I need to call an async method synchronously. How can I do that?

Async method:

public async Task<Customers> GetCustomers()
{
    return await Service.GetCustomersAsync();
}

Normal usage:

public async void GetCustomers()
{
    customerList = await GetCustomers();
}

I've tried using the following:

Task<Customer> task = GetCustomers();
task.Wait()

Task<Customer> task = GetCustomers();
task.RunSynchronously();

Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)

I also tried a suggestion from here, however it doesn't work when the dispatcher is in a suspended state.

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();
}

Here is the exception and stack trace from calling RunSynchronously:

System.InvalidOperationException

Message: RunSynchronously may not be called on a task unbound to a delegate.

InnerException: null

Source: 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()

解决方案

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

public static class AsyncHelpers
{
    /// <summary>
    /// Execute's an async Task<T> method which has a void return value synchronously
    /// </summary>
    /// <param name="task">Task<T> method to execute</param>
    public static void RunSync(Func<Task> task)
    {
        var oldContext = SynchronizationContext.Current;
        var synch = new ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(synch);
        synch.Post(async _ =>
        {
            try
            {
                await task();
            }
            catch (Exception e)
            {
                synch.InnerException = e;
                throw;
            }
            finally
            {
                synch.EndMessageLoop();
            }
        }, null);
        synch.BeginMessageLoop();

        SynchronizationContext.SetSynchronizationContext(oldContext);
    }

    /// <summary>
    /// Execute's an async Task<T> method which has a T return type synchronously
    /// </summary>
    /// <typeparam name="T">Return Type</typeparam>
    /// <param name="task">Task<T> method to execute</param>
    /// <returns></returns>
    public static T RunSync<T>(Func<Task<T>> task)
    {
        var oldContext = SynchronizationContext.Current;
        var synch = new ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(synch);
        T ret = default(T);
        synch.Post(async _ =>
        {
            try
            {
                ret = await task();
            }
            catch (Exception e)
            {
                synch.InnerException = e;
                throw;
            }
            finally
            {
                synch.EndMessageLoop();
            }
        }, null);
        synch.BeginMessageLoop();
        SynchronizationContext.SetSynchronizationContext(oldContext);
        return ret;
    }

    private class ExclusiveSynchronizationContext : SynchronizationContext
    {
        private bool done;
        public Exception InnerException { get; set; }
        readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
        readonly Queue<Tuple<SendOrPostCallback, object>> items =
            new Queue<Tuple<SendOrPostCallback, object>>();

        public override void Send(SendOrPostCallback d, object state)
        {
            throw new NotSupportedException("We cannot send to our same thread");
        }

        public override void Post(SendOrPostCallback d, object state)
        {
            lock (items)
            {
                items.Enqueue(Tuple.Create(d, state));
            }
            workItemsWaiting.Set();
        }

        public void EndMessageLoop()
        {
            Post(_ => done = true, null);
        }

        public void BeginMessageLoop()
        {
            while (!done)
            {
                Tuple<SendOrPostCallback, object> task = null;
                lock (items)
                {
                    if (items.Count > 0)
                    {
                        task = items.Dequeue();
                    }
                }
                if (task != null)
                {
                    task.Item1(task.Item2);
                    if (InnerException != null) // the method threw an exeption
                    {
                        throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
                    }
                }
                else
                {
                    workItemsWaiting.WaitOne();
                }
            }
        }

        public override SynchronizationContext CreateCopy()
        {
            return this;
        }
    }
}

这篇关于我将如何运行的异步任务&LT; T&GT;方法同步?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆