thrift 实战 —— 一个简单的匹配系统(下)

简介: thrift 实战 —— 一个简单的匹配系统(下)

上文,继续完善我们的匹配系统


image.png

完善 match_client


直接上代码:


...
# 1.从终端读取输入
from sys import stdin
def operate(op, user_id, username, score):
    transport = TSocket.TSocket('localhost', 9090)
    transport = TTransport.TBufferedTransport(transport)
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    client = Match.Client(protocol)
    transport.open()
    # 2.远程调用
    user = User(user_id, username, score)
    if op == "add":
        client.add_user(user, "")
    elif op == "remove":
        client.remove_user(user, "")
    transport.close()
def main():
    # 3.读取用空格分开的输入
    for line in stdin:
        op, user_id, username, score = line.split(" ")
        operate(op, int(user_id), username, int(score))
if __name__ == "__main__":
    main()
复制代码


读取输入,远程调用:


image.png


只需要简单修改几句 thrift 帮我们生成的代码,我们的客户端就大体完成了。


完善 match_server


关于匹配机制,有以下几点:


  • 定义一个消息队列,处理客户端传过来的 add_userremove_user 的命令
  • 定义一个用户池,将用户放到同一个用户池中来进行匹配
  • 添加和移除不能同时进行,要有锁
  • 经典的生产者-消费者问题


上代码,引入一些必要的头文件,然后定义消息队列的结构:


// match_server/main.cpp
...
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <unistd.h>
...
struct Task {
  User user;
  string type;
};
struct MsgQueue {
  queue<Task> q;
  mutex m;
  condition_variable cv;
}msg_queue;
复制代码


处理队列,消费者,注意锁的运用,没有消息时阻塞线程,等待唤醒:


void consume_task() {
  while(true) {
    unique_lock<mutex> lck(msg_queue.m);
    if (msg_queue.q.empty()) {
      msg_queue.cv.wait(lck);
    } else {
      auto task = msg_queue.q.front();
      msg_queue.q.pop();
      // 别忘了解锁
      lck.unlock();
      // 在用户池里添加或删除
      if (task.type == "add") pool.add(task.user);
      else if (task.type == "remove") pool.remove(task.user);
      // 每次处理完消息都在用户池进行一次匹配
      pool.match();
    }
  }
}
int main(int argc, char **argv) {
  ...
  cout << "Start match server 😎" << endl;
  // 开一个单独的线程给消费者
  thread matching_thread(consume_task);
  server.serve();
  return 0;
}
复制代码


添加以及移除用户方法,每次上锁只能有一个方法操作队列,然后唤醒消费线程:


class MatchHandler : virtual public MatchIf {
  public:
    MatchHandler() {
    }
    int32_t add_user(const User& user, const std::string& info) {
      printf("add_user\n");
      unique_lock<mutex> lck(msg_queue.m);
      msg_queue.q.push({user, "add"});
      msg_queue.cv.notify_all();
      return 0;
    }
    int32_t remove_user(const User& user, const std::string& info) {
      printf("remove_user\n");
      unique_lock<mutex> lck(msg_queue.m);
      msg_queue.q.push({user, "remove"});
      msg_queue.cv.notify_all();
      return 0;
    }
};
复制代码


新建用户池,用于匹配,这里采取了最简单的匹配方法,只要用户池里有两个人就匹配(后续可以优化):


class Pool {
  public:
    void save_result(int a, int b) {
      // 打印匹配结果
      printf("Match Result: %d %d\n", a, b);
    }
    void match() {
      while (users.size() > 1) {
        // 两个人就匹配
        auto a = users[0], b = users[1];
        users.erase(users.begin());
        users.erase(users.begin());
        save_result(a.id, b.id);
      }
    }
    void add(User user) {
      users.push_back(user);
    }
    void remove(User user) {
      for (uint32_t i = 0; i < users.size(); i++){
        if (users[i].id == user.id) {
          users.erase(users.begin()+i);
          break;
        }
      }
    }
  private:
    // 用户池
    vector<User> users;
}pool;
复制代码


编译运行,可以看到已经跑通了:


image.png


就到这里吧,具体代码可以查看github,后续优化手段有很多,我在这里抛砖引玉:


  • 分差
  • 时间
  • 多线程
  • ...
目录
相关文章
|
算法 安全 网络协议
slb高效的数据包转发能力
slb高效的数据包转发能力
152 7
|
11月前
|
vr&ar 图形学 云计算
实时云渲染与虚拟现实的结合:推动3D设计行业向更广阔领域拓展
3D设计行业面临四大难题:渲染时间长、审批流程复杂、成本高且设备更新快、渲染时电脑无法处理其他工作。实时云渲染通过云端算力,提供快速便捷的渲染解决方案,支持多人协同审批,大幅降低硬件成本,提高工作效率。平行云作为国内领先的实时云渲染服务商,已在全球范围内服务上千家企业,涵盖教育培训、数字孪生、医疗健康等多领域,助力3D设计行业高效解决现有难题。
301 18
|
11月前
|
机器学习/深度学习 人工智能 数据可视化
《AI与鸿蒙Next:建筑设计可视化的革新力量》
在建筑设计领域,可视化至关重要。人工智能通过快速生成方案、优化材质与纹理、智能照明模拟及细节增强,极大提升了设计效率和质量。鸿蒙Next图形渲染技术则凭借强大的物理渲染引擎、超分与超帧技术、智慧美学构图和多设备协同渲染,使建筑效果更加逼真细腻。两者的结合不仅缩短了设计周期,还增强了沟通协作,拓展了设计创意边界,为建筑设计行业带来了前所未有的变革与机遇。
225 4
|
12月前
|
机器学习/深度学习 人工智能 编解码
【AI系统】ESPNet 系列
本文介绍了ESPNet系列,专注于高分辨率图像的语义分割,强调了其高效的计算性能和低内存、功耗特性。ESPNet V1提出了ESP模块,通过分解标准卷积为point-wise卷积和空洞卷积金字塔,大幅减少了参数量和计算成本。ESPNet V2则进一步优化,采用了分组卷积和深度空洞分离卷积,增强了模型的有效感受野,同时降低了浮点计算量,适用于多种视觉任务。
268 11
|
安全 算法 Linux
Linux 服务器还有漏洞?建议使用 OpenVAS 日常检查!
在数字化时代,Linux 服务器的安全至关重要。OpenVAS 是一款优秀的开源漏洞扫描工具,可以帮助及时发现并修复服务器中的安全隐患。本文将介绍 OpenVAS 的主要功能、使用方法及应对漏洞的措施,帮助用户加强服务器安全管理,确保企业数字化安全。
411 7
|
安全 算法 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(10-2):保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali——Liinux-Debian:就怕你学成黑客啦!)作者——LJS
保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali以及常见的报错及对应解决方案、常用Kali功能简便化以及详解如何具体实现
|
XML Java 数据库
Spring boot的最全注解
Spring boot的最全注解
407 4
|
JSON 计算机视觉 数据格式
LangChain-17 FunctionCalling 利用大模型对函数进行回调 扩展大模型的额外的能力 比如实现加减乘除等功能
LangChain-17 FunctionCalling 利用大模型对函数进行回调 扩展大模型的额外的能力 比如实现加减乘除等功能
318 4
|
存储 关系型数据库 MySQL
【赵渝强老师】MySQL的Memory存储引擎
MySQL 的存储引擎层负责数据的存储和提取,支持多种存储引擎,如 InnoDB、MyISAM 和 Memory。InnoDB 是最常用的存储引擎,从 MySQL 5.5.5 版本起成为默认引擎。Memory 存储引擎的数据仅存在于内存中,重启后数据会丢失。示例中创建了使用 Memory 引擎的 test3 表,并展示了数据在重启后消失的过程。
227 0
|
数据可视化 搜索推荐 BI
哪些任务进度管理器值得推荐?几款工具使用测评
在快节奏的工作环境中,任务进度管理器成为提高效率和协作的关键工具。本文介绍了三款高效实用的管理软件:板栗看板、Trello 和 Asana。这些工具不仅帮助用户更好地规划和跟踪项目进度,还能确保任务按时完成。板栗看板以其直观的看板和灵活的自定义选项受到青睐;Trello 通过丰富的插件和跨平台支持,成为全球广泛使用的工具;Asana 则以强大的功能和灵活的工作流管理,适合大型企业和复杂项目的管理需求。用户可根据自身需求选择合适的工具,提高团队协作效率,达成项目目标。