使用boost :: asio :: ip :: tcp :: iostream的低带宽性能 [英] Low bandwidth performance using boost::asio::ip::tcp::iostream

查看:105
本文介绍了使用boost :: asio :: ip :: tcp :: iostream的低带宽性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have written a small test program that uses boost::asio::ip::tcp::iostream to transmit about 38 MiB of data:

#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;
}

处于释放模式的程序输出如下:

The output of the program in release mode looks like this:

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

传输148 MB(超过2分钟)花费了38 MB.我可以将数据复制到USB记忆棒中,并比boost::asio更快地手动将其移交.

It took 148 seconds (more than 2 minutes) to transfer 38 MB. I could copy the data to a USB stick and hand it over manually faster than boost::asio does.

有什么方法可以提高带宽性能?

Is there any way to improve bandwidth performance?

推荐答案

在从文本到文本的序列化中,您的时间可能浪费了.

Your time likely is wasted in the serialization to/from text.

对我来说,二进制存档中的拖放速度确实从80Mbit/s增加到872MBit/s:

Dropping in binary archive does increase the speed from 80Mbit/s to 872MBit/s for me:

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

以秒为单位的总时间减少为3s,这恰好是初始睡眠:)

The total time in seconds is reduced to 3s, which happens to be the initial sleep :)

概念验证 在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; }

警告:

这里有一件事情是丢失"的,旧版本的代码并没有真正支持它:直接面对面接收多个档案.

Caution:

One thing is "lost" here, that wasn't really supported with the old version of the code, either: receiving multiple archives directly head to head.

您可能希望使用某种成帧协议.参见例如

You might want to device some kind of framing protocol. See e.g.

  • Boost Serialization Binary Archive giving incorrect output
  • Outputting more things than a Polymorphic Text Archive
  • Streams Are Not Archives (http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/)

我已经在此处完成了许多"Boost序列化的开销"文章:

I've done a number of "overhead of Boost Serialization" posts on here:

  • how to do performance test using the boost library for a custom library
  • Boost C++ Serialization overhead

这篇关于使用boost :: asio :: ip :: tcp :: iostream的低带宽性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆