2011-08-21 21 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 
       ); 
     } 
    } 
}