2011-08-21 25 views
0
private static string GetProxy() 
{ 
    var rnd = new Random(); 
    if (Settings.Globals.UsedProxies.Count >= 100) 
    { 
     Settings.Globals.UsedProxies.Clear(); 
    } 

Start: 
    var inx = rnd.Next(0, Settings.Globals.Proxies.Count); 
    var theProx = Settings.Globals.Proxies[inx]; 
    foreach (var item in Settings.Globals.UsedProxies) 
    { 
     if (item == theProx) 
      goto Start; 
    } 
    Settings.Globals.UsedProxies.Add(theProx); 
    return theProx; 
} 

我从5个线程的池中以10到30秒的随机时间间隔调用此代码。这使用100%的CPU并且滞后于系统非常糟糕。如果我注释掉我对GetProxy的调用,应用程序只使用7%的CPU。有任何想法吗?为什么此功能使用100%的CPU?

这个想法是我有1000代理列表。一旦使用了proxie,我想将它添加到usedproxies列表中,并且从不使用已经使用过的代理。

+1

什么'Settings.Globals.UsedProxies'? – SLaks

+1

它使用100%的CPU多长时间? – ridecar2

+1

UsedProxies和Proxies都是列表。最初的代理列表数为1000。 –

回答

3

您的有趣 goto循环保证永久运行。
您的代码从列表中选取一个随机项目,循环直到找到该项目并重新开始。

一旦使用了所有的代理,你的代码将永远循环,因为它找不到任何更多的代理来添加。

另外,List<T>不是线程安全的,因此您的代码很可能以不可预知的方式失败。

+1

我不这么认为。它从一个列表中挑选一个随机项目('Proxies'),然后在另一个列表('UsedProxies')中查找它。 – svick

+0

你是对的;我没有注意到这一点。编辑。 – SLaks

+0

我不认为它会永远运行,直到它找到代理不在使用的代理。不是一个非常有效的方法来做到这一点。 – ridecar2

0

试试这个(假设UsedProxies所有代理可以在Proxies找到):

List<string> unusedProxies = new List<string>(Settings.Globals.Proxies); 
foreach (string proxy in Settings.Globals.UsedProxies) 
{ 
    unusedProxies.Remove(proxy); 
} 

int inx = rnd.Next(0, unusedProxies.Count); 
string proxy = unusedProxies[inx]; 
Settings.Globals.UsedProxies.Add(proxy); 
return proxy; 

这应该是比你的版本更快,因为所有未使用的代理是在自己单独的列表。然后,您可以使用rnd.Next来获取随机代理,并确保该代理未被使用。

1

为了回答实际问题,它使用了100%的CPU(在我假设的单个核心机器上),因为所有内容都足够小以适应内存,我们只是循环并进行一些检查。这非常耗费CPU资源。

要创建不使用代理服务器,你可以做以下的列表:

HashSet unused = new HashSet(Settings.Globals.Proxies); 
List unused = all.ExceptWith(Settings.Globals.UsedProxies); 
unused.ExceptWith(Settings.Globals.UsedProxies);

然后使用unused.Count财产和unused.GetEnumerator()选择从unused组随机代理。

+0

+1但HashSet .ExceptWith返回void IIRC(http://msdn.microsoft.com/en-us/library/bb299875.aspx)。 – FuleSnabel

+0

谢谢,现在修复。 – ridecar2

1

这严格来说不是对OP问题的答案(为什么这个函数需要100%的CPU),然而OPs有竞争条件的问题,这可能会导致列表行为不正常。所以我想我可以演示一种方法来处理该问题

据我所知,代码从代理列表中分配一个随机代理字符串。代码检查这是否已经是免费的,如果不是它试图挑选另一个代理字符串。

代码的问题之一是声明此代码是并发调用的,但代码不安全并发访问。

解决它的一种方法是引入一个ProxyPool类,以安全地处理并发访问。

下面是一些代码,可能是使用的关于如何建立一个ProxyPool类的起点:

namespace SO_ProxyPool 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics; 
    using System.Linq; 
    using System.Threading.Tasks; 

    sealed class ProxyPool 
    { 
     readonly object m_lock = new object(); 
     readonly Random m_random = new Random(); 
     readonly HashSet<string> m_usedProxies = new HashSet<string>(); 
     readonly HashSet<string> m_freeProxies = new HashSet<string>(); 
     volatile int m_minSize; 

     public ProxyPool (IEnumerable<string> availableProxies) 
     { 
      m_freeProxies = new HashSet<string> (availableProxies); 
      m_minSize = m_freeProxies.Count; 
     } 

     /// <summary> 
     /// Reserves a proxy, returns null if no proxy is available 
     /// </summary> 
     /// <returns>The reserver proxy or null if no proxy is available</returns> 
     public string ReserveProxy() 
     { 
      lock (m_lock) 
      { 
       if (m_freeProxies.Count == 0) 
       { 
        return null; 
       } 

       var index = m_random.Next (0, m_freeProxies.Count); 

       var proxy = m_freeProxies.ElementAt (index); 

       var removeSuccessful = m_freeProxies.Remove (proxy); 
       var addSuccessful = m_usedProxies.Add (proxy); 
       Debug.Assert (removeSuccessful); 
       Debug.Assert (addSuccessful); 

       m_minSize = Math.Min (m_minSize, m_freeProxies.Count); 

       return proxy; 
      } 
     } 

     /// <summary> 
     /// Returns the minimum size of the pool so far 
     /// </summary> 
     public int MinSize 
     { 
      get 
      { 
       return m_minSize; 
      } 
     } 

     /// <summary> 
     /// Frees a reserved proxy 
     /// </summary> 
     /// <param name="proxy">The proxy to free</param> 
     public void FreeProxy (string proxy) 
     { 
      if (proxy == null) 
      { 
       return; 
      } 

      lock (m_lock) 
      { 
       var removeSuccessful = m_usedProxies.Remove (proxy); 
       if (removeSuccessful) 
       { 
        var addSuccessful = m_freeProxies.Add (proxy); 
        Debug.Assert (addSuccessful); 
       } 

      } 
     } 
    } 

    class Program 
    { 
     static readonly ProxyPool s_proxyPool = new ProxyPool (
      new[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", } 
      ); 

     static string GetProxy() 
     { 
      return s_proxyPool.ReserveProxy(); 
     } 

     static void FreeProxy (string proxy) 
     { 
      s_proxyPool.FreeProxy (proxy); 
     } 

     static void SimplisticTestCase() 
     { 
      var proxy = GetProxy(); 
      // Do something relevant... 
      if (proxy != null) 
      { 
       FreeProxy (proxy); 
      } 
     } 

     static void Main (string[] args) 
     { 
      var then = DateTime.Now; 

      const int count = 10000000; 
      Parallel.For (0, count, idx => SimplisticTestCase()); 

      var diff = DateTime.Now - then; 

      Console.WriteLine (
       "#{0} executions took {1:0.00}secs, pool min size {2}", 
       count, 
       diff.TotalSeconds, 
       s_proxyPool.MinSize 
       ); 
     } 
    } 
}