# 加权轮训算法--最大公约数法

index表示本次请求到来时，选择的服务器的索引，初始值为-1；current_weight表示当前调度的权值，初始值为max(S)。

当请求到来时，从index+1开始轮询服务器数组S，找到其中权重大于等于current_weight的第一个服务器，用于处理该请求。记录其索引到结果序列中。

在轮询服务器数组时，如果到达了数组末尾，则重新从头开始搜索，并且减小current_weight的值：current_weight -= gcd(S)。如果current_weight等于0，则将其重置为max(S)。

demo代码：

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

typedef struct
{
int weight;
char name[2];
}server;

int getsum(int *set, int size)
{
int i = 0;
int res = 0;

for (i = 0; i < size; i++)
res += set[i];

return res;
}

int gcd(int a, int b)
{
int c;
while(b)
{
c = b;
b = a % b;
a = c;
}

return a;
}

int getgcd(int *set, int size)
{
int i = 0;
int res = set[0];

for (i = 1; i < size; i++)
res = gcd(res, set[i]);

return res;
}

int getmax(int *set, int size)
{
int i = 0;
int res = set[0];

for (i = 1; i < size; i++)
{
if (res < set[i]) res = set[i];
}

return res;
}

int lb_wrr__getwrr(server *ss, int size, int gcd, int maxweight, int *i, int *cw)
{
while (1)
{
*i = (*i + 1) % size;
if (*i == 0)
{
*cw = *cw - gcd;
if (*cw <= 0)
{
*cw = maxweight;
if (*cw == 0)
{
return -1;
}
}
}
if (ss[*i].weight >= *cw)
{
return *i;
}
}
}

void wrr(server *ss, int *weights, int size)
{
int i = 0;

int gcd = getgcd(weights, size);
int max = getmax(weights, size);
int sum = getsum(weights, size);

int index = -1;
int curweight = 0;

for (i = 0; i < sum; i++)
{
lb_wrr__getwrr(ss, size, gcd, max, &(index), &(curweight));
printf("%s(%d) ", ss[index].name, ss[index].weight);
}

printf("\n");
return;
}

server *initServers(char **names, int *weights, int size)
{
int i = 0;
server *ss = calloc(size, sizeof(server));

for (i = 0; i < size; i++)
{
ss[i].weight = weights[i];
memcpy(ss[i].name, names[i], 2);
}

return ss;
}

int main()
{
int i = 0;

int weights[] = {1, 2, 4};
char *names[] = {"a", "b", "c"};
int size = sizeof(weights) / sizeof(int);

server *ss = initServers(names, weights, size);

printf("server is ");
for (i = 0; i < size; i++)
{
printf("%s(%d) ", ss[i].name, ss[i].weight);
}
printf("\n");

printf("\nwrr sequence is ");
wrr(ss, weights, size);

return;
}

上面的代码中，算法的核心部分就是wrr和lb_wrr__getwrr函数。在wrr函数中，首先计算所有服务器权重的最大公约数gcd，权重最大值max，以及权重之和sum。

初始时，index为-1，curweight为0，然后依次调用lb_wrr__getwrr函数，得到本次选择的服务器索引index。

算法的核心思想体现在lb_wrr__getwrr函数中。以例子说明更好理解一些：对于服务器数组{a(1), b(2), c(4)}而言，gcd为1，maxweight为4。

第1次调用该函数时，i(index)为-1，cw(current_weight)为0，进入循环后，i首先被置为0，因此cw被置为maxweight。从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器是c，因此，i被置为2，并返回其值。

第2次调用该函数时，i为2，cw为maxweight。进入循环后，i首先被置为0，因此cw被置为cw-gcd，也就是3。从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器还是c，因此，i被置为2，并返回其值。

第3次调用该函数时，i为2，cw为3。进入循环后，i首先被置为0，因此cw被置为cw-gcd，也就是2。从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器是b，因此，i被置为1，并返回其值。

第4次调用该函数时，i为1，cw为2。进入循环后，i首先被置为2，从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器是c，因此，i被置为2，并返回其值。

第5次调用该函数时，i为2，cw为2。进入循环后，i首先被置为0，因此cw被置为cw-gcd，也就是1。从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器是a，因此，i被置为0，并返回其值。

第6次调用该函数时，i为0，cw为1。进入循环后，i首先被置为1，从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器是b，因此，i被置为1，并返回其值。

第7次调用该函数时，i为1，cw为1。进入循环后，i首先被置为2，从i开始轮询服务器数组ss，第一个权重大于等于cw的服务器是c，因此，i被置为2，并返回其值。

经过7（1+2+4）次调用之后，每个服务器被选中的次数正好是其权重值。