C++ 使用Boost Beast进行并发请求处理

C++ 使用Boost Beast进行并发请求处理,c++,boost-asio,boost-beast,C++,Boost Asio,Boost Beast,我指的是Beast存储库中的这个示例程序: 我对代码做了一些更改,以检查同时处理多个请求的能力 boost::asio::io_context ioc{1}; tcp::acceptor acceptor{ioc, {address, port}}; std::list<http_worker> workers; for (int i = 0; i < 10; ++i) { workers.emplace_back(acceptor, doc_root);

我指的是Beast存储库中的这个示例程序:

我对代码做了一些更改,以检查同时处理多个请求的能力

 boost::asio::io_context ioc{1};
 tcp::acceptor acceptor{ioc, {address, port}};

 std::list<http_worker> workers;
 for (int i = 0; i < 10; ++i)
 {
     workers.emplace_back(acceptor, doc_root);
     workers.back().start();
 }

 ioc.run();
这是我的问题:如果我同时向我的服务器发送两个
GET
请求,它们是按顺序处理的,我知道这一点,因为第二个“Simulate processing”语句是在前一个语句后约30秒打印的,这意味着在第一个线程上执行会被阻止

我试图阅读boost::asio的文档以更好地理解这一点,但没有效果

acceptor::async\u accept
的文档说明:

无论异步操作是否立即完成,都不会从此函数中>调用处理程序。处理程序的调用将以与使用boost::asio::io_service::post()进行>等效的方式执行

boost::asio::io\u service::post()的文档说明:

io_服务保证仅在当前正在调用run()、>run_one()、poll()或poll_one()成员函数的线程中调用处理程序

因此,如果10个工作进程处于
run()
状态,那么这两个请求为什么会排队


还有,有没有一种方法可以在不适应不同示例的情况下绕过这种行为?(例如)

io\u context
不会在内部创建线程来执行任务,而是使用显式调用
io\u context::run
的线程。在本例中,仅从一个线程(主线程)调用
io_context::run
。因此,只有一个线程用于执行任务,该线程在
sleep
中被阻塞,并且没有其他线程执行其他任务

要使此示例起作用,您必须:

  • 向池中添加更多线程(如您提到的第二个示例中所示)
  • size\t const threads\u count=4;
    std::向量v;
    v、 保留(线程数-1);
    对于(size_t i=0;i
  • 在需要同步的地方(至少对于套接字读写)添加同步(例如,使用第二个示例中的
    ),因为现在您的应用程序是多线程的
  • 更新1

    回答问题“如果实际上
    io_context
    仅在一个线程上运行,那么Beast示例(第一个引用的示例)中工作线程列表的用途是什么?”


    注意,不管线程数如何,这里的IO操作都是异步的,这意味着
    http::async\u write(socket\u…
    不会阻塞线程。请注意,我在这里解释了原始示例(不是您的修改版本)。这里的一名工作人员处理一次“请求-响应”往返。想象一下情况。有两个客户端client1和client2。Client1的internet连接不良(或请求很大的文件),而client2的情况正好相反。客户1提出请求。然后client2发出请求。因此,如果只有一个工作客户端,那么client2将不得不等到client1完成整个往返“请求-响应”。但是,由于有多个workers,client2会立即得到响应,而不是等待client1(请记住IO不会阻止单个线程)该示例针对瓶颈是IO而不是实际工作的情况进行了优化。在修改后的示例中,情况正好相反—与IO相比,工作(30秒)非常昂贵。对于这种情况,最好使用第二个例子。

    谢谢你的建议。如果您不介意我问一下,如果事实上io_上下文仅在一个线程上运行,那么Beast示例(第一个引用的示例)中的工作者列表的目的是什么?
        void accept()
        {
            // Clean up any previous connection.
            boost::beast::error_code ec;
            socket_.close(ec);
            buffer_.consume(buffer_.size());
    
            acceptor_.async_accept(
                socket_,
                [this](boost::beast::error_code ec)
                {
                    if (ec)
                    {
                        accept();
                    }
                    else
                    {
                         boost::system::error_code ec2;
                         boost::asio::ip::tcp::endpoint endpoint = socket_.remote_endpoint(ec2);
    
                        // Request must be fully processed within 60 seconds.
                        request_deadline_.expires_after(
                            std::chrono::seconds(60));
    
                        std::cerr << "Remote Endpoint address: " <<  endpoint.address() << " port: " << endpoint.port() << "\n";
    
                        read_request();
                    }
                });
        }
    
    
        void process_request(http::request<request_body_t, http::basic_fields<alloc_t>> const& req)
        {
            switch (req.method())
            {
            case http::verb::get:
                std::cerr << "Simulate processing\n";
                std::this_thread::sleep_for(std::chrono::seconds(30));
                send_file(req.target());
                break;
    
            default:
                // We return responses indicating an error if
                // we do not recognize the request method.
                send_bad_response(
                    http::status::bad_request,
                    "Invalid request-method '" + req.method_string().to_string() + "'\r\n");
                break;
            }
        }
    
    
    size_t const threads_count = 4;
    std::vector<std::thread> v;
    v.reserve(threads_count - 1);
    for(size_t i = 0; i < threads_count - 1; ++i) { // add thraed_count threads into the pool
        v.emplace_back([&ioc]{ ioc.run(); });
    }
    ioc.run(); // add the main thread into the pool as well