我正在尝试通过轮询服务器以获取数据更改并保持连接打开来实现彗星样式功能,直到有回应的东西。
首先,我的控制器上有一个静态变量,用于存储数据上次更新的时间:
public static volatile DateTime lastUpdateTime = 0;
因此,只要我轮询的数据发生变化,这个变量就会被改变。
然后我有一个Action,它将最后一次检索数据作为参数:
public ActionResult Push(DateTime lastViewTime)
{
while (lastUpdateTime <= lastViewTime)
{
System.Threading.Thread.Sleep(10000);
}
return Content("testing 1 2 3...");
}
因此,如果lastUpdateTime
小于或等于lastViewTime
,我们知道没有新数据,我们只是将请求保存在循环中,保持连接打开,直到那里是新信息,然后我们可以将其发送回客户端,客户端将处理响应然后发出新请求,因此连接基本上始终是打开的。
这似乎工作正常,但我担心线程安全,这可以吗? lastUpdateTime是否需要标记为volatile?还有更好的方法吗?
由于
编辑:也许我应该在更新时间值时使用锁定对象
private static object lastUpdateTimeLock = new object();
..
lock (lastUpdateTimeLock)
{
lastUpdateTime = DateTime.Now;
}
答案 0 :(得分:3)
关于您的原始问题,您必须小心DateTimes,因为它们是.NET运行时中的实际对象。只有少数几种数据类型可以原生访问(例如int,bools)而不需要锁定(假设您没有使用Interlocked)。如果您想避免日期时间的任何问题,您可以获得长时间的刻度并使用Interlocked类来管理它们。
也就是说,如果你在.NET应用程序中寻找彗星功能,那么你不得不比你在这里得到的更多。 IIS / ASP.NET无法使用您现在采用的方法进行扩展;在你达到100个用户之前,你会达到极限。除此之外,您还必须切换到使用异步处理程序,并为传入请求实现自定义有界线程池。
如果您真的想要一个经过测试的ASP.NET / IIS解决方案,请查看WebSync,它是专为此目的而设计的完整彗星服务器。
答案 1 :(得分:1)
老实说,我担心的是保持打开的连接数和空的while循环。您可能很好的连接,但我肯定想要进行一些负载测试以确保。
while (lastUpdateTime <= lastViewTime) {}
似乎应该有一个Thread.Sleep(100)
或其他内容。否则我认为它会不必要地消耗很多cpu周期。
由于前一个值无关紧要,lastUpdateTime = DateTime.Now
周围似乎没有锁定。如果它是lastUpdateTime = lastUpdateTime + 1
或其他什么,那么可能就可以了。