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,后续优化手段有很多,我在这里抛砖引玉:


  • 分差
  • 时间
  • 多线程
  • ...
目录
相关文章
|
6月前
|
数据采集 算法 Java
Java 正则表达式【匹配与分组基本原理】
Java 正则表达式【匹配与分组基本原理】
|
6月前
|
Java API Apache
ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
【4月更文挑战第11天】ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
70 11
|
12月前
|
JSON 自然语言处理 数据格式
分布式系列教程(33) -ElasticSearch DSL语言查询与过滤
分布式系列教程(33) -ElasticSearch DSL语言查询与过滤
194 0
|
6月前
|
Kubernetes Java 数据库连接
Flink问题之自定义分隔符写入如何解决
Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎。本合集提供有关Apache Flink相关技术、使用技巧和最佳实践的资源。
|
SQL 自然语言处理 索引
DSL的诞生 | 复杂sql转成Elasticsearch DSL深入详解
源自死磕ElasticsearchQQ群(626036393)中的一个问题: 问题如下: where (position=ES or work=ES or content=ES) and academic=本科 and (city=北京 or city=深圳) 1 怎么构建ES的查询条件? 我的问题拆解与实现如下:
1757 0
DSL的诞生 | 复杂sql转成Elasticsearch DSL深入详解
|
缓存 索引
白话Elasticsearch02- 结构化搜索之filter执行原理bitset机制与caching机制
白话Elasticsearch02- 结构化搜索之filter执行原理bitset机制与caching机制
94 0
|
存储 C++ Python
thrift 实战 —— 一个简单的匹配系统(上)
thrift 实战 —— 一个简单的匹配系统(上)
259 0
thrift 实战 —— 一个简单的匹配系统(上)
|
编译器 Apache
Thrift架构与使用方法
Thrift架构与使用方法
254 0
Thrift架构与使用方法
|
存储 自然语言处理 索引
深究|Elasticsearch单字段支持的最大字符数?
在业务系统中,遇到过两个问题: 问题1:设置为keyword类型的字段,插入很长的大段内容后,报字符超出异常,无法插入。 问题2:检索超过ignore_above设定长度的字段后,无法返回结果。
562 0
深究|Elasticsearch单字段支持的最大字符数?
|
自然语言处理 索引
Elasticsearch 如何实现查询/聚合不区分大小写?
1、实战问题 最近社区里有多个关于区分大小写的问题: 问题1:ES查询和聚合怎么设置不区分大小写呢? 问题2:ES7.6 如何实现模糊查询不区分大小写? 主要是如何进行分词和mapping的一些设置来实现这个效果, 自己也尝试过对setting 和 mapping字段进行设置,都是报错比较着急, 类似的问题,既然有很多同学问到,那么咱们就有必要梳理出完整的思路和方案。 这或许是铭毅天下公众号的使命所在。 这个问题不复杂,所以本文会言简意赅,直击要害!
852 0
Elasticsearch 如何实现查询/聚合不区分大小写?