2015-09-04 57 views
2

我们正在等待函数发生事件。但我认为该规范是不正确的(它有效,但对我来说它看起来错了!)。正确的等待方式事件

首先,这是代码我的同事写道:

public string Dispatch(Request data) 
    { 
     var uri = ... 
     string _result = null; 
     using (var ws = new WebSocket(uri)) 
     { 
      ws.OnMessage += (sender, e) => 
      { 
       _result = e.Data; 
      }; 

      ws.Send(request); 
      while (_result == null) 
      { 
       Thread.Sleep(10); 
      } 

      return _result; 
     } 
    } 

有没有意识到这更好的办法?我想我可以使用AutoResetEvent,但这是否更好?有没有一种方法可以实现代码,以便线程可以在等待答案时重用? (我知道如何与TaskCompletitionSource做到这一点,但是这也是正确的同步功能?)

我的想法是:

public string Dispatch(Request data) 
    { 
     var uri = ... 

     using (var ws = new WebSocket(uri)) 
     { 
      TaskCompletionSource<Guid> tcs; 
      ws.OnMessage += (sender, e) => 
      { 
       tcs.SetResult(e.Data); 
      }; 

      ws.Send(request); 

      return tcs.Task.Result; 
     } 
    } 

public string Dispatch(Request data) 
    { 
     var uri = ... 
     string _result = null; 
     var event = new AutoResetEvent(false); 
     using (var ws = new WebSocket(uri)) 
     { 
      TaskCompletionSource<Guid> tcs; 
      ws.OnMessage += (sender, e) => 
      { 
       _result = e.Data; 
       event.Set(); 
      }; 

      ws.Send(request); 

      event.WaitOne(); 
      return _result; 
     } 
    } 
+5

使用TCS进行异步处理。 – i3arnon

+1

_ [我可以在Stack Overflow上发布关于优化代码的问题吗?....不,它不是最好的地方 - 虽然它是关于主题的,但是对于这样的问题有更好的地方。您可以将代码复制到Code Review中 - 但请确保阅读他们的帮助中心,查看他们对一个好问题的期望。](http://meta.stackoverflow.com/questions/261841/can-i-post - 关于优化代码堆栈溢出)_ – MickyD

+0

我已经这样做了,但使用代码的公司不使用异步/等待... –

回答

0

有没有更好的办法意识到这一点?

几乎任何形式的等待都会比原来的代码更好,每隔10毫秒就会为了检查一个标志而醒来。唯一会更糟的是根本不要拨打Thread.Sleep()。但那只会更糟糕。

我想我可以使用AutoResetEvent,但是这样更好吗?

恕我直言,使用TaskCompletionSourceawait是最好的。这样做将解决您的下一个问题:

有没有一种方法来实现代码,线程可以重用,而它正在等待答案?

I.e.与await,线程实际上被释放用于其他用途。调用await的方法将返回await语句,允许该线程继续执行其他代码。当然,这意味着调用方法需要以某种方式处理异步;通常它的工作方式是async被推回到线程的顶部,例如,在某种事件分派循环中,例如Winforms或WPF中的循环。

你没有具体关于为什么你的公司没有使用await。如果限制是由于被锁定到早期版本的.NET中,则可能无法使用TaskCompletionSource,因为它只能在.NET 4及更高版本中使用。

即使您正在使用.NET 4(或更高版本)并且可以使用TaskCompletionSource,等待该任务也无法解决您对释放其他用途的线程的担忧。这可能是也可能不是可寻址的; Task类确实有ContinueWith()方法,该方法允许您在完成Task时明确提供要调用的继续委托。但是,如果您的Dispatch()方法本身不能用于异步上下文—,即在操作完成之前它不能返回—,那么除了在操作完成之前,您别无选择,只能阻止该线程的执行。

(根据—这太少了已经在这里提供的背景下能够提供具体的建议—这是可能的,你可以从调度等操作Dispatch()方法,同时它的等待,但是这会显著复杂化恕我直言,最好升级到.NET 4.5/C#5并使用await ......这可能不是一个长期维护问题,而是试图破解更现代版本的固有功能框架和语言)。

最后,我会注意到,作为一般规则,您应该避免使用ManualResetEventAutoResetEvent,因为它们基于非托管Windows同步对象,并且相当“重量级”。 .NET提供更高效的本机同步机制。至少,您可以使用Monitor类,使用Wait()Pulse()方法;可以使用CountdownEventSemaphoreSlim找到等效机制。每个语义都略有不同,但都可以用来轻松实现线程之间的简单信号。