【问题标题】:Low bandwidth performance using boost::asio::ip::tcp::iostream使用 boost::asio::ip::tcp::iostream 的低带宽性能
【发布时间】:2017-10-16 02:50:06
【问题描述】:

我编写了一个小测试程序,使用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;
}

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

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 分钟)。我可以将数据复制到 U 盘并手动传递,比 boost::asio 更快。

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

【问题讨论】:

    标签: c++ boost boost-asio boost-serialization


    【解决方案1】:

    您的时间可能浪费在序列化到/从文本中。

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

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

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

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

    注意:

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

    您可能想要设备某种帧协议。参见例如

    我在这里做了一些“Boost Serialization 开销”的帖子:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      相关资源
      最近更新 更多