2016-12-28 83 views
1

编辑:
我注意到这些滞后尖峰只发生在visual studio中调试时。如果我在Visual Stduio之外运行.exe,程序不会使用超过3%的CPU。任何人都可以告诉我为什么会发生这种情况?并行对于在2,3分钟后导致大规模滞后峰值


我也遇到过使用的Parallel.For检查大量代理(通过使webrequests)并行processing.I'm一个问题。这是我的函数:

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%。我不知道为什么会发生这种情况,因为它直到现在都运行良好。我希望有人能够帮助我理解导致这种情况的原因。
在这里你可以看到我的问题:Lag spikes here

+0

此外,这用于几天前工作正常。现在我有这个问题没有做任何改变的代码.. – Catalin

+0

您或许可以使用探查器来检查哪部分代码持有CPU。事实上你没有改变你的代码中的任何东西,因为它正常工作使我认为HttpRequest调用之一的行为可能与它前几天的表现不同,很可能是因为另一方的行为有不同的表现(网站)。 –

+0

@o_weisman如何使用探查器?我使用了默认的诊断工具,以及导致大部分CPU使用率的原因,它说外部代码。那是什么意思? – Catalin

回答

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方法可以使用实际的异步webcalls(我相信代码以前包含在您的文章中),我相信处理可以真正改善。

+0

如果您使'CheckProxies'返回'async Task'而不是'async void',我会让您满意。 –

+0

@ScottChamberlain这就是我的理由;)更改签名 –

+0

非常感谢您的帮助。在做了一些研究之后,似乎视觉工作室出现了滞后高峰,因为一次抛出大量异常(但不是100%肯定)。 – Catalin

0

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

通常,您不需要修改此设置。但是,您可以选择先进的使用场景,如这些明确设置:

  • 当你知道你正在使用一个特定的算法不会规模超过一定数目的核心。您可以设置属性以避免在其他内核上浪费周期。

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

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

我会尝试删除该值,看看你的应用程序的行为!