版权声明:本文为博主原创,欢迎转载,转载请注明链接地址。 https://blog.csdn.net/qq_30164225/article/details/85068128
想看上篇的童鞋请移步静态轮循调度算法实现
上篇说到,使用取模方式,没有办法实现公平轮询调度,于是有了这篇,采用引用计数的方式实现动态轮询调度。如下:
<?php
/**
* Class RoundCounter
* 动态公平循环分配实现算法
* 原理:
* 通过整体循环计数和成员循环计数实现轮循调度
* 数据结构:
*
* 权限人员集合 [1,2,3,4,5]
* 本组的轮循次数 1
* 人员初始化轮循次数:0
*
* 测试操作:
* 1.人员状态变更
* 2.组内人员变更 (不公平)
*/
class RoundCounter{
protected $members;
protected $loop;
protected $membersInfo = [];
public function __construct(array $members){
$this->members = $members;
$this->loop = 1;
//初始化 成员状态
foreach ($members as $member){
$memberInfo = $this->initStatus($member);
if($memberInfo['status'] == 1){
$this->membersInfo[] = $memberInfo;
}
}
echo '当前组内成员: '.json_encode($this->membersInfo).PHP_EOL;
}
//人员上/下线
private function initStatus($member){
$status = mt_rand(1,2);
return $info = array(
'id'=>$member,
'status'=>$status,
'loop'=>$this->loop-1 //当前被轮循次数
);
}
//todo 加减组内成员 如果能实现动态轮寻就完美了 静态有漏洞 会掠过部分客服
public function changeGroupMembers(){
// 新增一个成员
$add = $this->initStatus(6);
$add['status'] = 1;
array_push($this->membersInfo,$add);
echo '新增成员: 6 '.PHP_EOL;
// 减少一个成员
//$rand = mt_rand(0,count($this->membersInfo));
//array_splice($this->membersInfo,$rand,1);
}
//获取当前组成员列表
public function getMembers(){
return $this->members;
}
//重置循环
public function resetLoop(){
$this->loop = 1;
foreach($this->membersInfo as &$v){
$v['loop'] = 0;
}
}
//分配在线客服
public function choose(){
if($this->loop > 10){
$this->resetLoop();
}
$member1 = [];
foreach($this->membersInfo as &$member){
//轮循状态
if($member['loop'] == $this->loop-1){
echo '分配给: '.json_encode($member).PHP_EOL;
$member['loop'] +=1;
return $member1 = $member;
}
}
//轮循
if(!$member1){
$this->loop++;
return reset($this->membersInfo);
}
}
}
//测试参数
$a = new RoundCounter([1,2,3,4,5]);
echo '----第一轮调度-----'.PHP_EOL;
for($i = 1;$i<100;$i++){
$a->choose();
}
$a->choose();
echo '----结束-----'.PHP_EOL;
echo '----修改组内客服-----'.PHP_EOL;
$a->changeGroupMembers();
echo '----第二轮循调度-----'.PHP_EOL;
for($i = 1;$i<100;$i++){
$a->choose();
}
执行结果:
MacBook-2:Desktop lemon$ php RoundCounter.php
当前组内成员: [{"id":1,"status":1,"loop":0},{"id":2,"status":1,"loop":0},{"id":3,"status":1,"loop":0},{"id":4,"status":1,"loop":0}]
----第一轮调度-----
分配给: {"id":1,"status":1,"loop":0}
分配给: {"id":2,"status":1,"loop":0}
分配给: {"id":3,"status":1,"loop":0}
分配给: {"id":4,"status":1,"loop":0}
分配给: {"id":1,"status":1,"loop":1}
分配给: {"id":2,"status":1,"loop":1}
分配给: {"id":3,"status":1,"loop":1}
分配给: {"id":4,"status":1,"loop":1}
分配给: {"id":1,"status":1,"loop":2}
分配给: {"id":2,"status":1,"loop":2}
分配给: {"id":3,"status":1,"loop":2}
分配给: {"id":4,"status":1,"loop":2}
分配给: {"id":1,"status":1,"loop":3}
分配给: {"id":2,"status":1,"loop":3}
分配给: {"id":3,"status":1,"loop":3}
分配给: {"id":4,"status":1,"loop":3}
----结束-----
----修改组内客服-----
新增成员:6
----第二轮循调度-----
分配给: {"id":1,"status":1,"loop":4}
分配给: {"id":2,"status":1,"loop":4}
分配给: {"id":3,"status":1,"loop":4}
分配给: {"id":4,"status":1,"loop":4}
分配给: {"id":6,"status":1,"loop":4}
分配给: {"id":1,"status":1,"loop":5}
分配给: {"id":2,"status":1,"loop":5}
分配给: {"id":3,"status":1,"loop":5}
分配给: {"id":4,"status":1,"loop":5}
分配给: {"id":6,"status":1,"loop":5}
分配给: {"id":1,"status":1,"loop":6}
分配给: {"id":2,"status":1,"loop":6}
分配给: {"id":3,"status":1,"loop":6}
分配给: {"id":4,"status":1,"loop":6}
分配给: {"id":6,"status":1,"loop":6}
分配给: {"id":1,"status":1,"loop":7}
引用计数的方式,虽然看起来不那么高大上,比较朴素,但是却是最行之有效的方法。因为是原子操作,每个个体不受成员数量变更带来的算法影响,所以可以保证公平调度。(^__^) 嘻嘻……
有时候还是要仔细想想,多问问自己为什么这样写,是不是可以换个思路做的更好,才能不断进步。
(完)