c# - TPL - 减少后期延迟
问题描述
我正在构建一个网络爬虫,似乎 TPL 非常适合我的用例。这是我想到的流程:
GetCommentsFromA --| |-- NotifyC
|-- ExtractKeywords --|
GetCommentsFromB --| |-- NotifyD
本质上,存在三种类型的组件:收集器、转换器和通知器。收集者通过抓取不同的网站来收集评论,然后将评论传递给变形金刚。他们预计每 X 秒轮询一次网页。在这种情况下,唯一存在的转换器是负责从评论中提取关键字的转换器。他们本质上是永无止境的生产者。
我最初是通过扩展经典的生产者-消费者模型来实现的。我在收集器和变压器之间放置了一个缓冲块,在变压器和通知器之间放置了另一个。(实际上还有更多的事情发生,但这就是要点。)每个组件都独立地从其相应的缓冲区块发布和接收数据。也就是说,我觉得必须有一种更优雅的方法。
从那时起,我发现LinkTo
允许块相互连接,并且除了缓冲区块之外还有专门的块,所以我开始考虑以下几点:
var extractKeywords = new TransformBlock<string, string>(ExtractKeywords);
var notifyTarget = new ActionBlock<string, string>(NotifyTarget);
extractKeywords.LinkTo(notifyTarget);
然后我可以启动不同的收集器,它们或多或少地在单独的线程上执行以下操作:
public async Task CollectAsync()
{
while (true)
{
Page page = await website.DownloadLatestPageAsync();
foreach (string comment in page.Comments())
{
transformer.Post(comment);
}
await Task.Delay(ArbitraryDelay);
}
}
收集器将发布到前面片段中看到的转换块。然而,我确实对这种方法有所保留。首先,(这可能是由于我对异步、多线程和 TPL 不熟悉)我担心发布到转换块会产生延迟。理想情况下,我希望收集器花费尽可能少的时间将数据传输到变压器,但我似乎无法找到一种干净的方式来做到这一点。如果变压器很慢,呼叫Post
似乎会阻塞很长一段时间,我也不确定是否SendAsync
会处理这个问题。Task.Run
似乎是个坏主意……但我不知道。感觉就像我很接近,但缺少一些简单的东西。
解决方案
推荐阅读
- movesense - WbCmd Movesense:放置对象的麻烦
- ruby - centos 7上的乘客安装失败,请建议如何解决这个问题?
- r - dplyr::select() 对可能不存在的列重新排序
- python - 如何创建几个 DatetimeIndex 对象(熊猫)的差异集?
- pandas - 使用给定的索引级别和排序顺序堆叠和连接数据帧
- c# - HTTP 请求未使用“匿名”客户端身份验证方案授权
- c# - C# SqlDataAdapter 与来自多个数据库的表的 JOIN
- powershell - PowerShell today's date 4-15-2020 (get-date).AddMonths(-6).month) expecting 4-15-2019, getting 10/31/2020
- html - CSS - 如何使矩形的边变成三角形?
- html - 如何将按钮css设置为半阴影