1:lesson6
1.1:Thrift概述
Apache Thrift官网: https://thrift.apache.org/。
官网教程: https://thrift.apache.org/tutorial/。
官网推荐指南: https://diwakergupta.github.io/thrift-missing-guide/。
学习项目地址: https://git.acwing.com/grant_drew/thrift_lesson。
大佬详细课程笔记: https://git.acwing.com/fashen/thrift_learning。
C++多线程并发基础入门教程 - zizbee的文章 - 知乎: https://zhuanlan.zhihu.com/p/194198073。(看这个入门C++多线程)
《C++并发编程实战 第二版》 : https://www.bookstack.cn/read/CPP-Concurrency-In-Action-2ed-2019/README.md。
Thrift 是由 Facebook 开源的轻量级、跨语言 RPC 框架,为数据传输、序列化以及应用级程序处理提供了清晰的抽象和实现。我们可以通过中间语言 IDL 来定义 RPC 接口和数据类型,再通过编译器来生成不同语言对应的代码,最后基于这些自动生成的代码通过相应的编程语言来构建 RPC 客户端和服务端
Apache Thrift 软件框架,用于可扩展的跨语言服务开发,将软件堆栈与代码生成引擎相结合,构建在 C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、 Cocoa、JavaScript、Node.js、Smalltalk、OCaml 和 Delphi 等语言。
视频教程: https://www.bilibili.com/video/BV1j44y1q7fy。
Thrift非常有用,AcWing的saber和评测等等功能都是由Thrift实现的。
游戏匹配的微服务框架:
Thrift应用于不同节点的进程之间的调用。这其实是一个RPC模型(框架)。
- RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务
RPC最主要的作用就是用于服务调用。
1.2:Thrift实操
本地新建一个仓库用于Thrift学习。
完整项目讲解参考: https://git.acwing.com/fashen/thrift_learning。
1 | acs@5b4f3438bdf2:~$ mkdir thrift_lesson |
在Gitlab上创建空项目,然后将本地仓库推送到远端。
1 | acs@5b4f3438bdf2:~/thrift_lesson$ git remote add origin |
学习任务:实现“游戏”节点和“匹配系统”节点。
1 | acs@5b4f3438bdf2:~/thrift_lesson$ mkdir match_system # 匹配系统文件夹 |
参照Thrift_lesson仓库下的thrift文件夹下的example.thrift
编写thrift接口,是官网的一个示例文件。
开始编写match.thrift
:
1 | namespace cpp match_system # 定义命名空间,match_system是文件名 |
接下来实现匹配系统的服务端(match-server):C++实现
在本地match_system
文件夹下新建一个src
文件夹:
cd src
执行命令:thrift -r --gen cpp ../../thrift/match.thrift
,根据thrift文件生成相应cpp代码。
在src
目录下使用Linux tree命令查看目录内容:
1 | acs@5b4f3438bdf2:~/thrift_lesson/match_system/src$ tree |
这些都是Thrift实现好的代码。
1 | 将自动生成的gen-cpp文件名修改为match_server |
打开main.cpp
:(里面的提示都很贴心)
将添加和删除用户的两个函数,补充return 0;
,保存一下。
然后把cpp文件编译、连接、运行一下,看看是否有问题,没有就开始写代码。
g++ -c main.cpp match_server/*.cpp
,编译所有cpp文件,不连接。
1 | acs@5b4f3438bdf2:~/thrift_lesson/match_system/src$ g++ -c main.cpp match_server/*.cpp |
发现有错误需要修改,是头文件路径出错。
看到只有main.cpp
没有编译生成.o
文件,打开mian.cpp
。
头文件路径改成:"match_server/Match.h"
,然后编译main.cpp
。
然后链接:将目标文件和库文件整合为可执行文件。
g++ *.o -o main -lthrift
,后面的-lthrift
将Thrift的动态链接库整合进来。
就得到了main
可执行文件,在main.cpp
中添加提示信息,重新编译、链接、执行(只需要处理main.cpp
),使用:./main
运行文件。
修改main.cpp
:
引入<iostream>
,using namespace std;
,在server.serve();
之前cout << "start match-server!" << endl;
。
和别人合作最好不要写using namespace std;
,容易引起命名冲突。
1 | acs@5b4f3438bdf2:~/thrift_lesson/match_system/src$ ./main |
接着持久化仓库,最好把重定向文件和可执行文件删掉,只保留源文件,好习惯!推送到远端。
1 | acs@5b4f3438bdf2:~/thrift_lesson/match_system/src$ git add . |
接下来实现游戏的客户端(match-client):python实现
在本地game
文件夹下新建一个src
文件夹:
cd src
执行命令:thrift -r --gen py ../../thrift/match.thrift
,根据thrift文件生成相应python代码。(python2和python3都可以)
1 | 将自动生成的gen-py文件名修改为match_client |
参照Thrift_lesson仓库下的game/src/example_client.py
,编写客户端代码。
在src
下新建client.py
,把example抄进去,再修改。(client.py
完整代码见仓库game/src/
路径)
前四行配置python环境变量直接删掉。
测试一下客户端和服务端的连接是否正常:
先运行服务端:./main
,然后运行服务端:python3 client.py
。
改进client.py
后的测试:
一个Bug复盘:
执行./main
报错,9090已经占用。
经过一番百度之后,没有结果。
使用top
命令查看进程情况时,发现有2个tmux在运行(这个好像和会话数量没什么关系,不管了),恍然大悟。然后tmux ls
查看发现有2个会话正在运行,原来是上午的tmux没关,下午开了一个新的,把上午的会话kill就行了。成功解决Bug。
游戏和匹配系统之间构成一个生产者-消费者模型,需要用到多线程。
通过消息队列来实现生产者与消费者之间的缓冲。
消息队列介绍: https://www.jianshu.com/p/19a94c1c729b。
通过PV操作互斥信号量来解决生产者消费者问题。(看看王道视频)
C++多线程笔记: https://github.com/downdemo/Cpp-Concurrency-in-Action-2ed。
改进main.cpp
:
对于队列的相关操作,应该加锁保证只能有一个线程操作它。
修改完mian.cpp
之后重新编译、连接、运行:
g++ -c main.cpp
,g++ *.o -o main -lthrift -pthread
,连接thrift动态链接库和C++多线程动态链接库。
一个Bug复盘:
链接重定向文件报错,提示未定义引用。
通过ls
命令查看当前目录内容,发现src/match_system
下的cpp源文件未编译(之前删除了),
然后把所有源文件重新编译后链接,成功解决。
测试match-server version2.0
,成功!
接下来实现数据保存系统的客户端(save-client):C++实现
服务端已经实现好了,不需要做了。
编写save.thrift
:
1 | namespace cpp save_service |
cd ~/thrift_lesson/match_system/src
执行命令:
thrift -r --gen cpp ../../thrift/save.thrift
,根据thrift文件生成相应cpp代码。
1 | 将自动生成的gen-cpp文件名修改为save_client |
然后开始完善main.cpp
:去官网教程看看C++的客户端代码案例,抄过来
写完后保存,回到src
目录,编译:g++ -c save_client/*.cpp main.cpp
,链接:g++ *.o -o main -lthrift -ptherad
。
测试一下:
匹配成功,数据保存成功!
再添加两个用户,发现result
文件修改为3和4,1和2没有了。
git add
—>git commit -m "xxx"
。
改进匹配机制,原来的匹配系统只匹配前2个人,现在改进为匹配分差在50以内的2个人。
再次测试3.0,成功!
改进单线程—>多线程,提高效率。
将生产者由单线程扩展成多线程。
再次测试4.0,成功!
最后再来一次优化,加进来的用户,设等待时间为wt秒,就在[score-wt*50,score+wt*50]
区间内寻找匹配的用户。
再次测试5.0,成功!