1

编辑:
我注意到这些滞后峰值仅在 Visual Studio 中调试时发生。如果我在 Visual Stduio 之外运行 .exe,该程序不会使用超过 3% 的 CPU。谁能告诉我为什么会这样?


我遇到了并行处理的问题。我正在使用 Parallel.For 检查大量代理(通过发出 webrequests)。这是我的功能:

private ConcurrentBag<string> TotalProxies = new ConcurrentBag<string>();
private void CheckProxies()
{
    ParallelOptions pOptions = new ParallelOptions();
    pOptions.MaxDegreeOfParallelism = 100;
    int max = TotalProxies.Count;
    Invoke(new Action(() => { lbl_Status.Text = "Checking"; }));
    Parallel.For(0, max, pOptions, (index, loopstate) =>
    {
        string Proxy = TotalProxies.ElementAt(index);
        if (WebEngine.IsProxyWorking(Proxy))
        {
            WorkingProxies.Add(Proxy);
            workingp++;
            Invoke(new Action(() =>
            {
                lstv_Working.Items.Add(Proxy);
                lbl_Working.Text = workingp.ToString();
            }));
        }
        checkedp++;
        Invoke(new Action(() => { lbl_Checked.Text = checkedp.ToString(); }));

        if (Stop)
            loopstate.Stop();
    });
    Invoke(new Action(() => {
        lbl_Status.Text = "Idle";
    }));
}

我的问题如下:
该程序对于前 0-2000 个请求运行良好,其中 cpu 使用率约为 3-5%。然后,在 2-3 分钟后,我遇到了大量且频繁的延迟峰值,导致 CPU 使用率跳到 100%。我不知道为什么会发生这种情况,因为它直到现在都运行良好。我希望有人可以帮助我了解导致这种情况的原因。
在这里你可以看到我的问题:滞后尖峰在这里

4

2 回答 2

2

正如所承诺的异步/等待示例,虽然看到你的更新我不确定它是否会有所作为。但是由于它不适合评论,所以在这里发布;)

private ConcurrentBag<string> TotalProxies = new ConcurrentBag<string>();
private async Task CheckProxies()
{
    lbl_Status.Text = "Checking"; //NB, invoking is omitted assuming that CheckProxies is called from the UI thread itself
    var tasks = TotalProxies.Select(CheckProxy);
    await Task.WhenAll(tasks);
    lbl_Status.Text = "Idle";
}

private async Task<bool> CheckProxy(string p)
{   
    bool working = await Task.Run(() => WebEngine.IsProxyWorking(p)); //would be better if IsProxyWorking itself uses async methods and returns a task, so Task.Run isn't needed. Don't know if it's possible to alter that function?
    if(working)
    {
        WorkingProxies.Add(p);
        workingp++; //Interlocked.Increment is not necessary because after the await we're back in the main thread
        lstv_Working.Items.Add(p);  //are these items cleared on a new run? 
        lbl_Working.Text = workingp.ToString();
    }
    checkedp++;
    lbl_Checked.Text = checkedp.ToString(); 
    return working;
}

请注意,由于我无法测试实际代码,因此我不确定效率。您当前的代码可能会执行得更好。但是,如果该IsProxyWorking方法可以使用实际的异步网络调用(我相信您的帖子中以前包含该代码),我相信处理可以真正改善。

于 2016-12-28T14:00:09.810 回答
0

我不知道这是否与您的问题直接相关,但是将 MaxDegreeOfParallelism 设置为 100 并不好。您基本上是在告诉您的应用程序同时执行 100 个任务!根据MSDN

通常,您不需要修改此设置。但是,您可以选择在高级使用场景中显式设置它,例如:

  • 当您知道您使用的特定算法不会超出一定数量的核心时。您可以设置该属性以避免在其他内核上浪费周期。

  • 当您同时运行多个算法并想要手动定义每个算法可以利用多少系统时。您可以为每个设置一个 P:System.Threading.Tasks.ParallelOptions.MaxDegreeOfParallelism 值。

  • 当线程池的启发式方法无法确定要使用的正确线程数并可能最终注入太多线程时。例如,在长时间运行的循环体迭代中,线程池可能无法区分合理进度或活锁或死锁,并且可能无法回收为提高性能而添加的线程。在这种情况下,您可以设置该属性以确保您使用的线程数不超过合理数量。

我会尝试删除此值并查看您的应用程序的行为方式!

于 2016-12-28T12:24:51.323 回答