我们正在等待函数发生事件。但我不认为守则是正确的(它有效,但对我来说看起来不对!)。
首先,这是我的同事写的代码:
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;
}
}
答案 0 :(得分:0)
有没有更好的方法来实现这个目标?
几乎任何形式的等待都比原始代码更好,原始代码每隔10毫秒唤醒一次,只是为了检查一个标志。唯一更糟的是根本不打电话给Thread.Sleep()
。但那只会变得更糟。
我想我可以使用AutoResetEvent,但这样更好吗?
恕我直言,最好使用TaskCompletionSource
和await
。这样做可以解决您的下一个问题:
有没有办法实现代码,线程可以在等待答案时重用?
即。使用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
......这可能不是一个长期的维护问题,而不是试图入侵由更现代的框架和语言版本提供的功能。
最后,我会注意到,作为一般规则,您应该避免使用ManualResetEvent
和AutoResetEvent
,因为它们基于非托管Windows同步对象并且相当“重量级”。 .NET提供了更高效的本机同步机制。至少,您可以使用Monitor
类,Wait()
和Pulse()
方法;可以使用CountdownEvent
或SemaphoreSlim
找到等效机制。每个都有略微不同的语义,但都可以用来轻松地在线程之间实现一个简单的信号。