(一)静态轮循调度算法实现

业务场景

有一堆组,每组成员不定时进出组,且组内成员会有状态,要求实现请求过来时,轮询分配给特定状态的成员。于是想到了经典的Round-Robin算法,根据业务写了个demo,如下:

<?php

/**
 * Class RoundRobin
 * 不公平循环分配实现算法
 * 原理:
 *    通过取模实现轮循调度
 * 数据结构:
 *
 * 权限人员集合 [1,2,3,4,5]
 * 初始轮循指针位置:4
 *
 * 测试操作:
 * 1.人员状态变更
 * 2.组内人员变更 (不公平)
 */

class RoundRobin{
    protected $members;
    protected $initMod;

    public function __construct(array $members){
        $this->members = $members;
        $this->initMod = count($members) - 1;
        echo '当前组内成员: '.json_encode($this->members).PHP_EOL;
    }
    
    //人员上/下线
    private function checkStatus(){
        return mt_rand(1,4);
    }

    //todo 加减组内成员 如果能实现动态轮寻就完美了 静态有漏洞 会掠过部分客服
    public function changeGroupMembers(){
        $total = count($this->members);
        $id = mt_rand(0,$total-1);
        echo '准备删除成员: '.$id+1.PHP_EOL;
        array_splice($this->members,$id,1);
        //echo '准备添加成员: '.$id.PHP_EOL;
        //array_push($this->members,$total+1);
    }

    //获取当前组成员列表
    public function getMembers(){
        return $this->members;
    }

    //分配在线客服
    public function choose(){
        $total = count($this->members);
        $mod = $c = $total; //组成员id集合
        $j = $this->initMod;
        //echo '当前模数: '.$j.PHP_EOL;
        while($c > 0 ){
            //获取成员id
            $j =($j+1) % $mod;
            echo '选中目标: '.$this->members[$j].PHP_EOL;
            //获取成员在线状态
            $status = $this->checkStatus();
            //echo '在线状态: '.$status.PHP_EOL;
            if( $status != 1){
                $this->initMod = $j; //移动到下一个成员
                //echo '模数自增之后: '.$this->initMod.PHP_EOL;
                $c--;
                if($c == 0){ return -1;} //未找到
                continue;
            }else{
                $this->initMod = $j; //移动到下一个
                return $j;
            }
        }
    }
}

//测试参数
$a = new RoundRobin([1,2,3,4,5]);
echo '----第一轮调度-----'.PHP_EOL;
for($i = 1;$i<10;$i++){
    $a->choose();
}
echo '----结束-----'.PHP_EOL;

echo '----修改组内客服-----'.PHP_EOL;
$a->changeGroupMembers();
echo '----第二轮循调度-----'.PHP_EOL;
for($i = 1;$i<10;$i++){
    $a->choose();
}

执行结果:

MacBook-2:Desktop lemon$ php RoundRobin.php
当前组内成员: [1,2,3,4,5]
----第一轮调度-----
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 4
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 4
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 4
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 4
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 4
选中目标: 5
----结束-----
----修改组内客服-----
准备删除成员: 4
----第二轮循调度-----
选中目标: 2 //******第二轮调度跳过了1*******
选中目标: 3
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 5
选中目标: 1
选中目标: 2
选中目标: 3
选中目标: 5
选中目标: 1

结果显示,在模数变更之后,循环的指针没有跟着变更,导致的新一轮的调度中,有的成员被略过,还有可能被重复调度,具体得看剔除的位置。所以单单靠取模来轮询调度,有一定的缺陷,这种算法适合静态目标的轮询,但是如果要实现动态计算指针位置,也不是一个简单的算法,有违初衷。感兴趣的朋友可以研究下,我还没想到如何动态平衡指针,(ノへ ̄、)捂脸。。。但是有另一种算法也可以实现动态平衡,那就是——引用计数,请看下篇文章——动态轮循调度算法实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值