如何不用短路逻辑实现STL排序器的多条件比较?
摘要:前言 最近工期紧、任务多,没有时间更新博客,就水一期吧。虽然是水,也不能太水,刚好最近工作中遇到一个 sorter 多条件排序的问题,花费了半天时间来定位解决,就说说它吧。 背景 公司产品是一个跨端的数据传输 sdk,当下载资源时,会先从服
前言
最近工期紧、任务多,没有时间更新博客,就水一期吧。虽然是水,也不能太水,刚好最近工作中遇到一个 sorter 多条件排序的问题,花费了半天时间来定位解决,就说说它吧。
背景
公司产品是一个跨端的数据传输 sdk,当下载资源时,会先从服务器拉取一批 peer,每个 peer 是包含要下载资源分片的 p2p 端,每个节点有一个序号,sdk 根据这个值从小到大排序后依次选取 peer 进行连接,序号是由服务器决定的,主要根据地域、连通率、带宽等决定的,可以简化为下面的 demo:
#include <stdio.h>
#include <vector>
#include <string>
#include <algorithm>
struct PeerInfo
{
std::string peerid;
std::string ip;
short port;
int begin;
int end;
int seq;
void print(void);
};
void PeerInfo::print(void)
{
printf ("peer %s: %d, %s:%d, %d-%d\n",
peerid.c_str(), seq,
ip.c_str(), port, begin, end);
}
struct PeerInfoSorter
{
bool operator() (PeerInfo const& lhs, PeerInfo const& rhs) {
return lhs.seq < rhs.seq;
}
};
int main (void)
{
std::vector<PeerInfo> vpi;
// init this vector by server response
// ...
std::sort (vpi.begin(), vpi.end(), PeerInfoSorter());
for (auto it = vpi.begin(); it != vpi.end(); ++ it)
{
it->print();
}
}
在下载过程中会向服务器请求多次,每批返回的 peer 都放在一个容器中排序,但是序号是基于批的,多个批次之间的 peer 如果仅按照 seq 排序的话,就会将前面批次旧的 peer 排在前面,从而导致一些新 peer 没有机会被用到,发生饥饿现象。
问题的产生
了解到这个情况后,采取了按批和序号同时排序的方案,即为 peer 增加一个 batch 字段用于记录批号,在排序时只有 batch 相同时才去比较 seq,代码类似下面这样:
struct PeerInfo
{
std::string peerid;
std::string ip;
short port;
int begin;
int end;
int seq;
int batch;
void print(void);
};
void PeerInfo::print(void)
{
printf ("peer %s: %d-%d, %s:%d, %d-%d\n",
peerid.c_str(), batch, seq,
ip.c_str(), port, begin, end);
}
struct PeerInfoSorter
{
bool operator() (PeerInfo const& lhs, PeerInfo const& rhs) {
return lhs.batch < rhs.batch || lhs.seq < rhs.seq;
}
};
当时的想法比较直接,先比较 batch,如果 batch 已经小了就直接短路返回结果;再比较 seq。
