在进行许多Http请求时,缓冲区大小不足或队列已满

时间:2017-03-24 15:52:00

标签: c# concurrency wikipedia-api

我目前正在尝试使用他们的公共API从维基百科中获取大量有关视频游戏的数据。我已经有了一些方法。我现在可以通过相关文章pageid获得我需要的所有title。但后来我需要得到他们的唯一标识符(Qxxxx,其中x是数字),这需要相当长的时间......可能是因为我必须对每个标题进行单一查询(有22031)或者因为我不明白维基百科查询。

所以我想"为什么不一次做多个查询?"所以我开始研究它,但我在标题中遇到了这个问题。程序运行一段时间(通常为3-4分钟)大约一分钟后,应用程序崩溃,标题中出现错误。我认为这是因为我的方法很糟糕:

ConcurrentBag<Entry> entrybag = new ConcurrentBag<Entry>(entries);
Console.WriteLine("Getting Wikibase Item Ids...");
Parallel.ForEach<Entry>(entrybag, (entry) =>
{
    entry.WikibaseItemId = GetWikibaseItemId(entry).Result;
});

以下是调用的方法:

async static Task<String> GetWikibaseItemId(Entry entry)
{
    using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }))
    {
        client.BaseAddress = new Uri("https://en.wikipedia.org/w/api.php");
        entry.Title.Replace("+", "Plus");
        entry.Title.Replace("&", "and");
        String queryString = "?action=query&prop=pageprops&ppprop=wikibase_item&format=json&redirects=1&titles=" + entry.Title;
        HttpResponseMessage response = await client.GetAsync(queryString);

        response.EnsureSuccessStatusCode();

        String result = response.Content.ReadAsStringAsync().Result;
        dynamic deserialized = JsonConvert.DeserializeObject(result);
        String data = deserialized.ToString();
        try
        {
            if (data.Contains("wikibase_item"))
            {
                return deserialized["query"]["pages"]["" + entry.PageId + ""]["pageprops"]["wikibase_item"].ToString();
            }
            else
            {
                return "NONE";
            }
        }
        catch (RuntimeBinderException)
        {
            return "NULL";
        }
        catch (Exception)
        {
            return "ERROR";
        }
    }
}

只是为了好的衡量,这里是入门级:

public class Entry
{
    public EntryCategory Category { get; set; }
    public int PageId { get; set; }
    public String Title { get; set; }
    public String WikibaseItemId { get; set; }
}

任何人都可以帮忙吗?我只需要更改查询或其他内容的方式吗?

1 个答案:

答案 0 :(得分:1)

从一个进程并行启动大约22000个http请求太多了。如果您的计算机拥有无限的资源和互联网连接带宽,这将接近拒绝服务攻击。

您看到的是TCP / IP端口耗尽或队列争用。要解决它,请以较小的块处理数组,例如获取10个项目,并行处理这些项目,然后获取下一个项目,依此类推。

特别是Wikimedia sites have a recommendation以串行方式处理请求:

  

读取请求没有硬性和快速限制,但我们要求您体谅并尽量不要关闭网站。大多数系统管理员保留在您危及其网站稳定性的情况下毫不客气地阻止您的权利。

     

如果您按顺序而不是并行提出请求(即等待一个请求在发送新请求之前完成,这样您就不会同时发出多个请求),那么您一定很好。

请务必检查其API服务条款,以了解是否符合以及并行请求的数量。