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} 条数据");
}
}
}
}