【问题标题】:await asynchronous method where completion is signalled by event handler等待异步方法,其中由事件处理程序发出完成信号
【发布时间】:2013-09-28 23:01:46
【问题描述】:

我正在使用 Windows Phone 8 中的联系人对象,从异步方法中调用 SearchAysnc。 SearchAsync 要求处理程序订阅 SearchCompleted 事件,并通过事件参数之一传递其结果,异步方法需要它来完成其工作(包括调用其他异步方法)。

您如何等待事件的异步完成,即事件模式和异步/等待模式之间的桥梁?

我能想出的唯一解决方案是使用 EventWaitHandle,在等待的任务中等待它,如下所示:

using System.Threading;


async Task<string> MyMethod()
{
    string result = null;
    Contacts cons = new Contacts();
    EventWaitHandle handle = new EventWaitHandle(false,EventResetMode.ManualReset);
    cons.SearchCompleted += (sender,args) =>
    {
        // I do all my work on the results of the contact search in this handler
        result = SomeOtherSynchronousOperation(args.Results);

        // When I'm done, I release the thread which was waiting for the results
        handle.Set();
    };
    cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");

    // I can't block this thread (or can I?)
    // So, I launch a task whose sole job is to wait
    await Task.Run(()=>
    {
       // This gets released by the Contacts.SearchCompleted handler when its work is finished,
       // so that MyMethod can finish up and deliver its result
       handle.WaitOne();
    }

    await DoOtherStuffWithResult(result);

    return result;
}

我的实际解决方案(不完全如上所示)确实有效。尽管上面的代码并不能准确地代表实现的解决方案(可能是一两个编译问题),但它应该有助于表达概念并说明我的问题的重点。

这让我想知道这是否是等待事件处理程序执行的唯一方法,或者接近最佳实践方法的任何地方,如果不是,那么执行此处所需操作的“最佳实践”是什么。

Windows 同步原语在 async/await 世​​界中仍然占有一席之地吗?

(根据提供的答案)

这是正确的吗?

using Microsoft.Phone.UserData;

string ExtractWhatIWantFromResults(IEnumerable<Contact> results)
{
    string result;

    // Do my processing on the list of contacts, stuff the results into result

    return string;
}

async Task<string> MyMethod()
{
    Contacts cons = new Contacts();
    TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();

    cons.SearchCompleted += (sender,args) =>
    {
        tcs.TrySetResult(ExtractWhatIWantFromResults(args.Results));
    };
    cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");

    return tcs.Task;
}

【问题讨论】:

    标签: c# .net multithreading asynchronous


    【解决方案1】:

    TaskCompletionSource是常用的使用方式。

    未测试(不知道如何在不知道您的类/方法的情况下进行测试),

    Task<string> MyMethodAsync()
    {
        Contacts cons = new Contacts();
        TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
    
        cons.SearchCompleted += (sender,args) =>
        {
            tcs.TrySetResult(args.Results);
        };
        cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");
    
        return tcs.Task;
    }
    

    【讨论】:

    • @L.B 此方法不需要 async 修饰符-仅当此方法使用 await 时才需要(此方法不需要)。将返回 Task 的方法命名为“Async”也是一种好习惯,例如 MyMethodAsync。
    【解决方案2】:

    要桥接 EAP 和 TAP,您应该use TaskCompletionSource,例如:

    public static Task<IEnumerable<Contact>> SearchTaskAsync(this Contacts contacts, string filter, FilterKind filterKind)
    {
      var tcs = new TaskCompletionSource<IEnumerable<Contact>>();
      EventHandler<ContactsSearchEventArgs> subscription = null;
      subscription = (_, e) =>
      {
        contacts.SearchCompleted -= subscription;
        tcs.TrySetResult(e.Results);
      };
      contacts.SearchCompleted += subscription;
      contacts.SearchAsync(filter, filterKind, null);
      return tcs.Task;
    }
    

    你可以这样使用:

    async Task<string> MyMethodAsync()
    {
      Contacts cons = new Contacts();
      var searchResults = await cons.SearchTaskAsync(String.Empty, FilterKind.None);
      string result = SomeOtherSynchronousOperation(searchResults);
      await DoOtherStuffWithResult(result);
      return result;
    }
    

    事实上,MSDN docs for TAP 的质量确实非常高,我强烈建议您通读整个部分。

    Windows 同步原语在 async/await 世​​界中仍然占有一席之地吗?

    没有那么多,因为一旦你阻塞了一个线程,你就失去了异步代码的好处。也就是说,您可以使用基于 TAP 的原语来模拟类似的行为; Stephen Toub has a series of blog entries 探索了这一点,我在 AsyncEx library 中实现了类似的原语。

    【讨论】:

      猜你喜欢
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      相关资源
      最近更新 更多