gpt4 book ai didi

c++ - 使用 boost::asio::ip::tcp::iostream 的低带宽性能

转载 作者:行者123 更新时间:2023-11-30 03:31:41 27 4
gpt4 key购买 nike

我写了一个小测试程序,它使用 boost::asio::ip::tcp::iostream 传输大约 38 MiB 的数据:

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/asio.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

using namespace std;

class Message {
public:
Message() {
}

virtual ~Message() {
}

string text;
std::vector<int> bigLoad;

private:
friend class boost::serialization::access;

template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &text;
ar &bigLoad;
}
};

BOOST_CLASS_EXPORT(Message)

void runClient() {
// Give server time to startup
this_thread::sleep_for(chrono::milliseconds(3000));

boost::asio::ip::tcp::iostream stream("127.0.0.1", "3000");
// const boost::asio::ip::tcp::no_delay option(true);
// stream.rdbuf()->set_option(option);

Message message;

stringstream ss;
ss << "Hello World!";
message.text = ss.str();

int items = 10000000;
int size = sizeof(int) * items;

std::cout << "Size in Byte = " << size << endl;
std::cout << "Size in KiB = " << size / 1024 << endl;
std::cout << "Size in MiB = " << size / 1024 / 1024 << endl;

for (int i = 0; i < items; i++)
message.bigLoad.push_back(i);

boost::archive::text_oarchive archive(stream);

cout << "Client start to send message" << endl;
try {
archive << message;
} catch (std::exception &ex) {
cout << ex.what() << endl;
}
cout << "Client send message" << endl;

stream.close();
cout << "Client shutdown" << endl;
}

void handleIncommingClientConnection(boost::asio::ip::tcp::acceptor &acceptor) {
boost::asio::ip::tcp::iostream stream;
// const boost::asio::ip::tcp::no_delay option(true);
// stream.rdbuf()->set_option(option);

acceptor.accept(*stream.rdbuf());

boost::archive::text_iarchive archive(stream);

while (true) {
try {
Message message;
archive >> message;
cout << message.text << endl;
} catch (std::exception &ex) {
cout << ex.what() << endl;

if (stream.eof()) {
cout << "eof" << endl;
stream.close();
cout << "Server: shutdown client handling..." << endl;
break;
} else
throw ex;
}
}
}

void runServer() {
boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 3000);
boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);

handleIncommingClientConnection(acceptor);
}

template <typename TimeT = std::chrono::milliseconds>
struct measure {
template <typename F, typename... Args>
static typename TimeT::rep execution(F &&func, Args &&... args) {
auto start = std::chrono::steady_clock::now();
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
auto duration = std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now() - start);
return duration.count();
}
};

void doIt() {
thread clientThread(runClient);
thread serverThread(runServer);

clientThread.join();
serverThread.join();
}

int main(int argc, char **argv) {
std::cout << measure<std::chrono::seconds>::execution(doIt) << std::endl;

return 0;
}

程序在 Release模式下的输出如下所示:

Size in Byte = 40000000
Size in KiB = 39062
Size in MiB = 38
Client start to send message
Client send message
Client shutdown
Hello World!
input stream error
eof
Server: shutdown client handling...
148

传输 38 MB 需要 148 秒(超过 2 分钟)。与 boost::asio 相比,我可以将数据复制到 USB 内存棒并手动将其移交。

有什么方法可以 boost 带宽性能吗?

最佳答案

您的时间可能浪费在与文本之间的序列化上。

对我来说,放入二进制存档确实可以将速度从 80Mbit/s boost 到 872MBit/s:

Client start to send message
Client send message
Client shutdown
Received: Hello World!
3

以秒为单位的总时间减少到3s,刚好是初始 sleep :)

概念验证 Live On Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/asio.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

using namespace std;

class Message {
public:
Message() {}

virtual ~Message() {}

string text;
std::vector<int> bigLoad;

private:
friend class boost::serialization::access;

template <class Archive> void serialize(Archive &ar, const unsigned int /*version*/) {
ar & text & bigLoad;
}
};

BOOST_CLASS_EXPORT(Message)

void runClient() {
// Give server time to startup
this_thread::sleep_for(chrono::seconds(1));

boost::asio::ip::tcp::iostream stream("127.0.0.1", "3000");
const boost::asio::ip::tcp::no_delay option(false);
stream.rdbuf()->set_option(option);

Message message;

stringstream ss;
ss << "Hello World!";
message.text = ss.str();

int items = 8 << 20;

for (int i = 0; i < items; i++)
message.bigLoad.push_back(i);

boost::archive::binary_oarchive archive(stream);

cout << "Client start to send message" << endl;
try {
archive << message;
} catch (std::exception &ex) {
cout << ex.what() << endl;
}
cout << "Client send message" << endl;

stream.close();
cout << "Client shutdown" << endl;
}

void handleIncommingClientConnection(boost::asio::ip::tcp::acceptor &acceptor) {
boost::asio::ip::tcp::iostream stream;
// const boost::asio::ip::tcp::no_delay option(false);
// stream.rdbuf()->set_option(option);

acceptor.accept(*stream.rdbuf());

boost::archive::binary_iarchive archive(stream);

{
try {
Message message;
archive >> message;
cout << "Received: " << message.text << endl;
} catch (std::exception &ex) {
cout << ex.what() << endl;

if (stream.eof()) {
cout << "eof" << endl;
stream.close();
cout << "Server: shutdown client handling..." << endl;
return;
} else
throw;
}
}
}

void runServer() {
using namespace boost::asio;
using ip::tcp;

io_service ios;
tcp::endpoint endpoint = tcp::endpoint(tcp::v4(), 3000);
tcp::acceptor acceptor(ios, endpoint);

handleIncommingClientConnection(acceptor);
}

template <typename TimeT = std::chrono::milliseconds> struct measure {
template <typename F, typename... Args> static typename TimeT::rep execution(F &&func, Args &&... args) {
auto start = std::chrono::steady_clock::now();
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
auto duration = std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now() - start);
return duration.count();
}
};

void doIt() {
thread clientThread(runClient);
thread serverThread(runServer);

clientThread.join();
serverThread.join();
}

int main() { std::cout << measure<std::chrono::seconds>::execution(doIt) << std::endl; }

注意:

这里“丢失”了一件事,旧版本的代码也没有真正支持它:直接接收多个文件。

您可能想要设备某种框架协议(protocol)。参见例如

我在这里发表了很多“Boost 序列化的开销”帖子:

关于c++ - 使用 boost::asio::ip::tcp::iostream 的低带宽性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44011333/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com