【问题标题】:Is it possible to call an Asynchronous call Synchronously?是否可以同步调用异步调用?
【发布时间】:2011-04-04 23:48:01
【问题描述】:

我在下面放置了一些非常基本的代码来说明我正在尝试做的事情。我有执行异步操作的“DoSomethingAshnc”方法。我希望 'DoSomething' 方法是一个同步方法,它不接受 action 参数并返回一个 int。

public void DoSomething(Action<int> actionToPerformOnComplete)
    {
        DoSomethingAsync(delegate(int val)
            {
                actionToPerformOnComplete(val);
            });
    }

是否甚至可以让“DoSomething”返回一个整数,就好像该方法是同步发生的一样?

【问题讨论】:

  • 你可以将它包装在一个线程中并阻塞,直到你得到响应......
  • 这就是为什么我们兴奋地等待C#5.0 async / await(或已经使用异步 CTP)。

标签: c# asynchronous delegates


【解决方案1】:

您需要在同步方法的末尾添加一些内容,告诉它等待另一个调用完成。我假设您的异步方法将有一个事件通知调用者何时完成。

如果是这样,那么我建议使用 ManualResetEvent 之类的东西,在同步线程中等待它,然后在 Finish 事件接收器中为异步设置它。

例子:

public void DoSomething(Action<int> actionToPerformOnComplete)
{
   ManualResetEvent mre = new ManualResetEvent(false);
   DoSomethingAsync(delegate(int val)
   {
      try
      {
         actionToPerformOnComplete(val);
      }
      finally
      {
         mre.Set();
      }
   });
   mre.WaitOne();
}

【讨论】:

  • 你可能应该使用mre.WaitOne(TimeSpan),这样你就可以处理异步事件调用Set失败的情况。如果发生这种情况,并且永远不会调用 mre.Set(),您的代码将永远挂起。
  • 确实如此。我会稍微更新我的代码,所以你不需要添加时间跨度。虽然使用 TimeSpan 很好,但如果你不需要计算最大执行时间,那就更好了。
  • 你是对的。您的代码比时间跨度要好得多。事实上,我从来没有意识到这种模式。我现在要去做一点重构......
  • 正是我需要的!谢谢:)
【解决方案2】:

正如其他人所提到的,您需要等待异步方法完成。要做到这一点而不将 Action 参数传递给您的方法,请使用以下代码:

public int DoSomething()
{
   int result;
   ManualResetEvent mre = new ManualResetEvent(false);
   DoSomethingAsync(val => {result = val; mre.Set(); });
   mre.WaitOne();
   return result;
}

这会执行异步方法,等待它完成并将结果分配给局部变量。返回此结果。

【讨论】:

    【解决方案3】:

    是的。你所要做的就是把这行代码:

    IAsyncResult asycn = ... // make a call to Async and get back IAsyncResult 
    while(!asycn.IsCompleted)
    {
       Thread.Sleep( ....);
    }
    

    更新

    正如一些人所问的,正确设计的异步操作将实现async pattern MSDN:

    使用异步操作 IAsyncResult 设计模式是 实现为两个名为 开始操作名称和 EndOperationName 开始和结束 异步操作 OperationName 分别。为了 例如,FileStream 类提供 BeginRead 和 EndRead 方法 从文件中异步读取字节。 这些方法实现了 异步版本的读取 方法。

    【讨论】:

    • ManualResetEvent 不是更好的选择吗?
    • 虽然 Thread.Sleep() 不是阻塞方法?认为最好不要在可能的情况下使用它。
    • 是的,它正在阻塞 - 就像 ManualResetEvent 一样阻塞,不多也不少 - 关键是,他想等待它完成。
    • 我的意思不是在这个意义上阻止。例如,在使用 Thread.Sleep 的 UI 线程上会阻止消息泵,我不确定 ManualResetEvent 是否会这样做。
    • 这让我想知道你从哪里得到 DoSomethingAsync 甚至返回某些东西的信息(更不用说 IAsyncResult).. :)
    【解决方案4】:
    using System;
    using System.Threading;
    
    namespace qqq
    {
        class Program
        {
            public static void DoAsync(Action<int> whenDone)
            {
                new Thread(o => { Thread.Sleep(3000); whenDone(42); }).Start();
            }
    
            static public int Do()
            {
                var mre = new ManualResetEvent(false);
    
                int retval = 0;
                DoAsync(i => { retval = i; mre.Set(); });
    
                if (mre.WaitOne())
                    return retval;
                throw new ApplicationException("Unexpected error");
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine(Do());
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-17
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      • 2016-03-24
      • 1970-01-01
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多