如何不用短路逻辑实现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。
阅读全文