using JiShe.CollectBus.FreeRedisProvider; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace JiShe.CollectBus.Common.Helpers { /// /// 设备组负载控制 /// public class DeviceGroupBalanceControl { /// /// 分组集合 /// private static List[] _cachedGroups; /// /// 设备分组关系映射 /// private static Dictionary _balancedMapping; /// /// 初始化缓存并强制均衡 /// public static void InitializeCache(List deviceList,int groupCount = 50) { // 步骤1: 生成均衡映射表 _balancedMapping = CreateBalancedMapping(deviceList, groupCount); // 步骤2: 根据映射表填充分组 _cachedGroups = new List[groupCount]; for (int i = 0; i < groupCount; i++) { _cachedGroups[i] = new List(capacity: deviceList.Count / groupCount + 1); } foreach (var deviceId in deviceList) { int groupId = _balancedMapping[deviceId]; _cachedGroups[groupId].Add(deviceId); } } /// /// 通过 deviceId 获取所在的分组集合 /// public static List GetGroup(string deviceId) { if (_balancedMapping == null || _cachedGroups == null) throw new InvalidOperationException("缓存未初始化"); int groupId = _balancedMapping[deviceId]; return _cachedGroups[groupId]; } /// /// 通过 deviceId 获取分组Id /// public static int GetDeviceGroupId(string deviceId) { if (_balancedMapping == null || _cachedGroups == null) throw new InvalidOperationException("缓存未初始化"); return _balancedMapping[deviceId]; } /// /// 创建均衡映射表 /// /// 数据集合 /// 分组数量 /// 允许的最大偏差百分比 /// public static Dictionary CreateBalancedMapping(List deviceList, int groupCount, int maxDeviation = 5) { var mapping = new Dictionary(); int targetPerGroup = deviceList.Count / groupCount; int maxAllowed = (int)(targetPerGroup * (1 + maxDeviation / 100.0)); // 初始化分组计数器 int[] groupCounters = new int[groupCount]; foreach (var deviceId in deviceList) { int preferredGroup = GetGroupId(deviceId, groupCount); // 如果首选分组未满,直接分配 if (groupCounters[preferredGroup] < maxAllowed) { mapping[deviceId] = preferredGroup; groupCounters[preferredGroup]++; } else { // 寻找当前最空闲的分组 int fallbackGroup = Array.IndexOf(groupCounters, groupCounters.Min()); mapping[deviceId] = fallbackGroup; groupCounters[fallbackGroup]++; } } return mapping; } /// /// 分析分组分布 /// /// /// /// public static Dictionary AnalyzeDistribution(List deviceList, int groupCount) { Dictionary distribution = new Dictionary(); foreach (var deviceId in deviceList) { int groupId = GetGroupId(deviceId, groupCount); distribution[groupId] = distribution.TryGetValue(groupId, out var count) ? count + 1 : 1; } return distribution; } /// /// 获取设备ID对应的分组ID /// /// /// /// public static int GetGroupId(string deviceId, int groupCount) { int hash = Fnv1aHash(deviceId); // 双重取模确保分布均匀 return (hash % groupCount + groupCount) % groupCount; } /// /// FNV-1a哈希算法 /// /// /// public static int Fnv1aHash(string input) { const uint fnvPrime = 16777619; const uint fnvOffsetBasis = 2166136261; uint hash = fnvOffsetBasis; foreach (char c in input) { hash ^= (byte)c; hash *= fnvPrime; } return (int)hash; } /// /// 打印分组统计数据 /// public static void PrintDistributionStats() { var stats = _cachedGroups .Select((group, idx) => new { GroupId = idx, Count = group.Count }) .OrderBy(x => x.GroupId); Console.WriteLine("分组数据量统计:"); foreach (var stat in stats) { Console.WriteLine($"Group {stat.GroupId}: {stat.Count} 条数据"); } } } }