基于重量的循环模式

时间:2015-01-17 18:26:14

标签: java


我正在尝试用Java编写一个简单的算法来选择哪个服务器需要执行一个操作。我想使用一种循环法,但每台服务器上都有一个重量。到目前为止,我编写了以下代码:

public static void main(String[] args) {
    // Weight for each server
    int x = 1;
    int y = 3;

    int counterx = 0;
    int countery = 0;

    for (int ii = 0; ii < 10; ii++) {
        counterx++;
        countery++;
        if (counterx == x) {
            System.out.println("Chosen x ");
            counterx = 0;
        }
        if (countery == y) {
            System.out.println("Chosen y ");
            countery = 0;
        }
    }

}

因此给定了两个服务器x和y,我已经存储了权重以分配给x和y变量中的每个服务器以及每个服务器的计数器。这似乎有效,但是如果服务器数量增加,代码将变得非常复杂。是否有任何util包可以帮助我根据权重因子确定要调用的服务器?
感谢

1 个答案:

答案 0 :(得分:7)

实际上,实现NavigableMap的类型是理想的,例如TreeMap

您需要执行以下操作:

  1. 封装您的服务器详细信息(名称,地址,选择权重)
  2. 存储服务器列表(稍后可以添加/删除)
  3. 选择介于0和所有权重之和的随机数。
  4. 在服务器列表中搜索第一台服务器,其中包含此服务器的所有服务器的权重总和大于随机值。
  5. 这样,列表中服务器的排序就不重要了。这正是与NavigableMap方法一起使用的ceilingEntry

    例如:

    public class ServerDetails {
        int weight;
        String address;
        public Server(int weight, String address) { 
            this.weight = weight;
            this.address = address;
        }
        public int getWeight(){return this.weight;}
        public String getAddress(){return this.address;}
    }
    

    然后使用以下内容定义服务器池:

    public class ServerPool {
        Random someRandGen = new Random();
        TreeMap<Integer, ServerDetails> pool;
        int totalWeight;
    
        public void init(ArrayList<ServerDetails> servers) {
            this.pool = new TreeMap<Integer, ServerDetails>();
            // create the "weighted selection" list
            totalWeight = 0;
            for(ServerDetails s : servers) {
                //  associate each server with the sum of the weights so far
                totalWeight += s.getWeight();
                this.pool.put(totalWeight, s);
            }
        }
    
        public ServerDetails getNext() {
            int rnd = someRandGen.nextInt(this.totalWeight);
            return pool.ceilingEntry(rnd).getValue();
        }
    }
    

    然后,您可以相应地为池定义添加/删除方法。与以下示例代码一起使用时,每个选择的次数百分比为:

    a: 11.1%
    b: 40.8%
    c: 19.6%
    d: 28.5%

    代码:

    ArrayList<ServerDetails> servers = new ArrayList<ServerDetails>(){{
        add(new ServerDetails(10, "a"));
        add(new ServerDetails(40, "b"));
        add(new ServerDetails(20, "c"));
        add(new ServerDetails(30, "d"));
    }}; 
    
    ServerPool serverPool = new ServerPool();
    serverPool.init(servers);
    for (int i = 0; i < 10000; i++)
        System.out.println(serverPool.getNext().getAddress());