我们在函数中等待事件发生。但我不认为代码是正确的(它有效,但对我来说它看起来是错误的!)。
起初,这是我同事写的代码:
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;
}
}
最佳答案
Is there a better way to realize this?
几乎任何形式的等待都会比原始代码好,原始代码每 10 毫秒醒来一次,只是为了检查一个标志。唯一会更糟的是不打电话 Thread.Sleep()
根本。但这只会更糟。
I think I can use AutoResetEvent, but is this better?
恕我直言,使用 TaskCompletionSource
与 await
是最好的。这样做可以解决您的下一个问题:
Is there a way to realize the Code that the Thread can be reused while it is waiting for an answer?
即与 await
,线程实际上被释放用于其他用途。方法调用 await
将在 await
返回语句,允许该线程继续执行其他代码。当然,这意味着调用方法需要以某种方式处理异步;通常它的工作方式是 async
一直被推回到线程的顶部,例如在某种事件调度循环中,例如在 Winforms 或 WPF 中发现的循环。
您没有具体说明为什么您的公司没有使用 await
.如果限制是由于被锁定到早期版本的 .NET,您可能无法使用 TaskCompletionSource
要么,因为它仅在 .NET 4 及更高版本中可用。
即使您使用的是 .NET 4(或更高版本)并且可以使用 TaskCompletionSource
,等待任务无法解决您对释放线程以供其他用途的担忧。这可能是可寻址的,也可能不是可寻址的; Task
类确实有 ContinueWith()
方法,它允许您显式提供一个继续委托(delegate),以便在 Task
完成时调用.但是如果你的 Dispatch()
方法本身不能在异步上下文中使用——即它在操作完成之前不能返回——那么你别无选择,只能阻止该线程的执行,直到操作完成。
(取决于上下文——此处提供的内容太少,无法提供具体建议——您可以在 Dispatch()
方法等待时分派(dispatch)其他操作。但这会使设计大大复杂化。恕我直言,最好只升级到 .NET 4.5/C# 5 并使用 await
……这可能不是一个长期维护问题,而是试图破解固有的功能由更现代的框架和语言版本提供)。
最后,我会指出,作为一般规则,您应该避免 ManualResetEvent
和 AutoResetEvent
,因为它们基于非托管 Windows 同步对象并且相当“重量级”。 .NET 提供了更高效的 native 同步机制。至少,您可以使用 Monitor
类,与 Wait()
和 Pulse()
方法;可以使用 CountdownEvent
找到等效机制或 SemaphoreSlim
.每种语义略有不同,但都可用于轻松实现线程间的简单信号。
关于c# - 等待事件的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32392790/