用处1:小组有N个耗时不等的任务,小组有M个能力不等的人,将任务进行合理的平均分配。
用处2:数据库表的关系表需要分表,如漫画的图片链接表每个漫画的图片数量不同,按服务器的性能进行分配数据。
计算推导
分数值:33,47,22,6,38,56
序号及权重:A:1 B:2 C:3
1.每人轮流按顺序拿
A: 33,6
B:47,38
C:22,56
2.将任务耗时降序排序按ABC顺序轮询拿
分数值:56,47,38,33,22,6
序号及权重:A:1 B:2 C:3
A: 56,33
B: 47,22
C: 38,6
3.在2的基础上ABC每轮询一次后按拿的分数升序,分数低的先拿(贪婪分配?这时候权重算是1:1了)
分数值:56,47,38,33,22,6
序号及权重:A:1 B:2 C:3
A: 56,6
B: 47,22
C: 38,33
(开始平均了)
4.在3的基础上为ABC加入权重,但是轮询一次后已拿的分数除以权重(权重分数)再进行升序
因为数据量不大,跟3的结果一样,但是用代码随机生成测试,分配不是很合理
5.将权重看作次数,分数按顺序分配,按权重分数升序拿,每拿一次权重减1,某个单位权重为0时分数不分配给该单位。全部单位权重都为0时恢复权重值重新轮询一次,就是下面代码的逻辑,分配还算平均
public class Services
{
/// <summary>
/// 权重
/// </summary>
public int Weight { get; set; }
/// <summary>
/// 权重计算
/// </summary>
public int WeightCalc { get; set; }
/// <summary>
/// 权重分数
/// </summary>
public decimal WeightScore { get; set; }
/// <summary>
/// 序号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 做个记录
/// </summary>
public List<int> ScopeRecord { get; set; } = new List<int>();
}
class Program
{
static void Main(string[] args)
{
//待分配的数据组数
int dataGroupCount = 100;
//服务器数量
int servicesCount = 7;
//需要平均分配的数据 22,66,4,7,863
List<int> DataCount = new List<int>();
List<Services> Service = new List<Services>();
//生成随机数据
for (int i = 0; i < dataGroupCount; i++)
{
DataCount.Add(new Random().Next(0,123));
}
//生成服务器随机数据
for (int i = 0; i < servicesCount; i++)
{
var weight = new Random().Next(1, servicesCount);
Service.Add(new Services()
{
Id = i,
Weight = weight, /*new Random().Next(1, servicesCount),*/ //随机权重
WeightCalc = weight,
WeightScore = 0
});
}
//数据组排序
DataCount = DataCount.OrderByDescending(q => q).ToList();
//轮询拿数据组数值 每轮询一次 根据权重分数重新分配先拿的人 且先拿高分数
//因为是数据组是降序最后分配不够拿时按权重分配也会将差距缩小
//用数据组进行轮询 也可以用服务器组轮询
foreach (var scope in DataCount)
{
//可优化
var empty = Service.OrderBy(q => q.WeightScore / q.Weight).FirstOrDefault(q => q.WeightCalc > 0);
empty.WeightScore += scope;
empty.ScopeRecord.Add(scope);
empty.WeightCalc--;
if (Service.Count(q=>q.WeightCalc>0)<=0)
{
Service.ForEach(q=>{q.WeightCalc = q.Weight;});
}
}
//打印服务器数据
foreach (var item in Service.OrderBy(q=>q.Id))
{
Console.WriteLine($"服务器号:{item.Id},服务器权重:{item.Weight},服务器分数:{item.WeightScore}");
Console.WriteLine($"分数记录:{string.Join(",",item.ScopeRecord)}");
Console.WriteLine();
}
//打印数据组数据
int colum = 10;
Console.WriteLine("数据组数据:");
for (int i = 0; i <= DataCount.Count / colum; i++)
{
Console.WriteLine($"{string.Join(",", DataCount.Skip(i * colum).Take(colum))}");
}
}
}