perl - 如何知道 PSGI 非阻塞流式编写器何时以 PSGI 兼容的方式准备好接收更多数据?
问题描述
我正在编写一个 PSGI 中间件,目前在 Twiggy 服务器上运行。中间件处理大型 (>2GB) 动态创建的文件并利用 Twiggy/AnyEvent 的异步流传输能力。
PSGI规范非常简要地说明了流式响应:
...响应者必须返回另一个实现
write
和close
方法的对象。...
挖掘 Twiggy 代码,它用于AnyEvent::Handle::push_write
实现上述write
方法。如果您继续向其提供大量数据的速度比将其写入网络的速度要快,这将耗尽您的所有 RAM。
当然AnyEvent::Handle
有方法并利用回调来处理缓冲区大小(即on_drain
事件处理程序来指示写入缓冲区何时为空并wbuf_max
限制写入缓冲区大小)。
然而,使用这些特性将是非常特定于服务器的,并且会限制 PSGI 应用程序的可移植性。PSGI 规范似乎没有涵盖用于控制/监视异步写入流或访问底层文件句柄/描述符以进行手动检查的 API。
其他人如何解决内存使用/缓冲问题或知道异步写入何时以跨 PSGI Web 服务器“兼容”的方式完成?任何指针都会很棒。
解决方案
作为后续行动,我想我会发布一个简化版本,说明我如何解决我的问题,以防它帮助其他人。
使用 in 中使用的{handle}
元素,我手动设置了和的回调。AnyEvent::Handle
writer
on_drain
on_error
当on_drain
写缓冲区为空时调用。因此,处理程序使我的数据生成代码能够继续生成数据。
当调用数据生成回调时,数据被写入响应并禁用/暂停数据生成。
当on_drain
处理程序再次启用数据生成时,循环继续。
这可以保持writer
检查的内存使用情况,现在使用最少的内存来处理大型流式响应。我似乎仍然有一些缓慢的内存泄漏问题,但这可能很深,我是我在其他地方的代码。
sub call {
my ($self,$env)=@_;
#URL/path matching here
my $myASYNCObject; #Complicated async object setup
my $onDrain= sub { #on_drain handler
$myAsyncObject->continue; #tell generation code to continue
};
return sub {
#Boilerplate for streaming response
my $responder=shift;
my $resCode=200;
my $resHeaders=[...];
my $writer=$responder->([$resCode,$resHeaders]);
#Setup callback and start data generation
$myAsyncObject->setCallback=sub{
my $myData=shift;
$writer->write->($myData); #Write the data
$myAsyncObject->pause; #Tell generation code to pause
};
$writer->{handle}->on_drain( #Setup on_drain handler
sub {
$myAsyncObject->continue; #tell generation code to continue
}
);
#Error handlers here...
}
}
推荐阅读
- javascript - 如何从以下函数传递参数以打印?
- node.js - 用于执行长时间运行的后台任务的 Node.js 库
- python - 使用 python 的 Codility 课程 MaxCounters 是否可能比 O(N+M) 更好?
- git - 无法从 Git 存储库中提取记录
- python-3.x - 有没有办法在线程上运行烧瓶?
- python - 如何在python中的请求中传递curl选项?
- c++ - 将指针向量推入 std::map
- android - 我怎么知道我的应用是由 Google 助理打开的,而不是正常启动的
- snapchat - 具有 DAY 粒度的时间序列查询的开始时间必须是帐户时区的开始时间 (00:00:00)
- c - 在 C 中释放二维数组(检查指针是否为 NULL)