c#-在ASP.Net/SignalR环境中使用System.Threading.Timer的风险

我们在独立的ASP.Net应用程序中运行SignalR,该应用程序在ASP.Net主网站的虚拟目录中运行.

在我们的SignalR集线器实现中,我们有一个静态的ConcurrentDictionary< int,UserState>.在各个连接中保持一些轻量级用户状态的变量.随着时间的流逝,该变量将根据客户端操作(即新用户开始与我们的网站进行互动)添加到该变量.这个变量本质上提供了跨连接的一些简单状态跟踪.

我们不特别希望添加一个特殊的SignalR背板,因为它的数据负载可能相对较轻,并且跟踪该内存应该足够,所以这将需要其他基础结构依赖性.

当用户长时间处于非活动状态(例如1个小时)时,我们希望将其从字典变量中删除.无论执行什么过程,都应确保该过程在一致的基础上运行-因此,不取决于用户的行为,而取决于定时的持续时间.

我相信这样做是一个很好的解决方案:

public class UserStateService : IUserStateService
{
    private static readonly ConcurrentDictionary<int, UserState> recentUsers = new ConcurrentDictionary<int, UserState>();
    private static Timer timer;

    public static void StartCleanup()
    {
        timer = new Timer( CleanupRecentUsers, null, 0, 60000 );
    }

    public static void StopCleanup()
    {
        timer.Dispose();
    }

    private static void CleanupRecentUsers( object state )
    {
        var now = DateTime.UtcNow;

        var oldUsers = recentUsers.Select( p => p.Value ).Where( u => u.LastActionTime.AddHours( 1 ) > now );

        foreach ( var user in oldUsers )
        {
            UserState removedUser;
            recentUsers.TryRemove( user.UserId, out removedUser );
        }
    }

    // other code for adding/updating user state.
}

如前所述,我认为这是一个很好的解决方案.但是,我对线程管理不是很熟悉(尽管我知道在ASP.Net中处理静态对象很危险).

StartCleanup()和StopCleanup()分别在应用程序生命周期的开始和结束时分别被调用一次. UserStateService是通过IoC容器(结构图)提供给我们的Hub类的,并且当前不具有任何特殊的生命周期处理范围(即,它不是Singleton或线程作用域的,只是按实例请求).

我们已经在生产应用程序中使用了静态并发字典,并且它们在没有任何已知的性能问题实例的情况下运行良好.我不确定在这里运行Timer循环.

因此,我的问题是,这里是否存在我需要缓解的明显风险,这些风险与线程被阻塞/锁定(或由于某种原因导致的CPU使用通常失控)或可能使这种方法行不通?

解决方法:

按照您建议的方式使用Timer并没有特别的问题.

但是,您的代码有两个问题.

首先,您有:

var oldUsers = recentUsers
               .Select( p => p.Value )
               .Where( u => u.LastActionTime.AddHours( 1 ) > now );

这将删除最后一个活动在最后一个小时内的所有用户.因此,您在一分钟前看到的任何人都将被移除.结果是您的“最近用户”列表在大多数情况下可能为空.充其量,它将包含至少一个小时前最后一次出现的用户.

我认为您想将其更改为<.或者,换一种方式思考:

.Where((now - u.LastActionTime) > TimeSpan.FromHours(1));

也可能存在竞争状况,因为选择要删除的用户可能在实际发生删除之前就发出了请求,因此最终您删除了刚刚提出请求的用户.但是,该竞赛条件的时间范围非常狭窄,可能不值得担心.

上一篇:在Android中实现Signal R


下一篇:一、Signalr WebApi客服-客户链接