boost::async_write 大文件和内存消耗

Posted

技术标签:

【中文标题】boost::async_write 大文件和内存消耗【英文标题】:boost::async_write large files and memory consumption 【发布时间】:2017-04-12 09:24:42 【问题描述】:

我正在使用 boost::asio 编写一个 Http Server。对于大文件,为了避免将整个文件读入内存并发送到网络,我使用 boost::asio::async_write 在网络上逐段读取。

问题是我的生产者(从文件中读取的函数)比消费者(boost::asio::async_write)快得多,这导致大文件的内存消耗很大。

我想通过限制缓冲区列表来避免这个问题。这似乎是一个简单的生产者/消费者问题,但是,我不想在这样做时阻塞线程。

我将 boost::io_service 与可配置的 n 个线程的线程池一起使用,如果我们对大文件有太多请求,我不想让服务器不再提供任何请求。

所以我的问题是: - 如何在不阻塞线程的情况下设计这种机制? - 我是否应该测试列表大小,然后如果它已经太大,生成一个截止时间计时器,它将执行 io_service::post 并继续阅读我的文件? - 有没有更好的处理方法?

【问题讨论】:

好吧。假设您通过 async_write 发送 N 个字节。启动您的 async_write 并同时从文件中读取接下来的 N 个字节(发布 2 个任务)。然后当你的 async_write 完成时,重复同样的事情。因此,您不会将任何尚未发送的文件部分保存在内存中。 【参考方案1】:

如果你想防止dos攻击,阻塞读取线程不是一个好主意。您要避免的是同时分配过多的资源(内存)。但是打开文件流的数量也是有限的。如果您在过载情况下开始阻塞读取线程,您可以非常快速地获得大量打开的文件流。如果您发现错误,您的程序可能不会崩溃,但这肯定是不受欢迎的行为,因为您无法打开其他文件(例如日志文件)。

为防止出现此问题,您必须同时关注这两种资源。有许多算法可以限制分配的资源量。对于内存,您可以为读取数据块使用环形缓冲区。您还可以使用原子计数器来跟踪分配的资源量并建立上限。信号量也可以用来解决这类问题。我更喜欢最后一个。伪代码看起来像这样。

Semaphore filestreams(maxNumberOfFilestreams);
Semaphore memory(maxNumberOfAllocatedChunks);

// Worker thread to read
void run() 
    filestream.wait();
    while(!eof) 
        memory.wait();
        // Allocate and read
    
    file.close();
    filestream.notify()


// Sending thread()

void run() 
    while(true) 
        // grab chunk, send and free memory
        memory.notify();
    

请记住,打开的 tcp 连接也是有限的资源。

【讨论】:

以上是关于boost::async_write 大文件和内存消耗的主要内容,如果未能解决你的问题,请参考以下文章

boost::async_write 在写入一段时间后失败

boost async_write() 和 non_blocking socket.send() 之间的区别

boost async_write:如果失败,如何跟踪未发送的内容并通知客户端/用户失败的内容?

C#大文件读取和查询--内存映射

Core Audio 大(压缩)文件播放和内存占用

Linux内存管理和大文件