这严格来说不是对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
);
}
}
}
什么'Settings.Globals.UsedProxies'? – SLaks
它使用100%的CPU多长时间? – ridecar2
UsedProxies和Proxies都是列表。最初的代理列表数为1000。 –