2017-09-27 57 views
0

我有這個問題,我似乎無法得到這個工作...C#的Parallel.For仍然不正確的索引與concurrentList包裝

我身邊有我的名單的包裝,使其線程安全。 但是,索引仍然不能在我的parallel.for循環中工作。

 public ConcurrentList<ConcurrentList<string>> multipleData(ConcurrentList<string> Adresses, ConcurrentList<string> PostalCodes) 
    { 
     ConcurrentList<ConcurrentList< string>> data = new ConcurrentList<ConcurrentList<string>>(); 
     ServicePointManager.DefaultConnectionLimit = 100; 
     Parallel.For(0, Adresses.Count, new ParallelOptions { MaxDegreeOfParallelism = 100 }, i => 
     { 
      WebClient web = new WebClient(); 
      string textFromUrl = web.DownloadString("https://website1.com" + Adresses[i] + " " + PostalCodes[i]); 
      ConcurrentList<string> dataElement = new ConcurrentList<string>(); 
      if (textFromUrl.Split(':', ',')[1] == "1") 
      { 
       textFromUrl = web.DownloadString("https://website2.com" + textFromUrl.Split('"', '"')[11]); 
       textFromUrl = web.DownloadString("https://website3.com" + textFromUrl.Split('"', '"')[3]); 
       ConcurrentList<RootObject> obj = JsonConvert.DeserializeObject<ConcurrentList<RootObject>>(textFromUrl); 
       dataElement.Add(obj[0].hoofdadres.geocodeerServiceZoekString); 
       dataElement.Add(obj[0].gebruiksdoel); 
       dataElement.Add(obj[0].begindatum.ToString());  
      } 
      else 
      { 
       dataElement.Add("empty"); 
       dataElement.Add("empty"); 
       dataElement.Add("empty"); 
      } 
       data.Add(dataElement); 
     }); 
     return data; 
    } 

我將返回的數據導出到excel工作表。問題是返回的數據被混淆了,所以iteration0不在數據[0]中,迭代10不在數據中[10]。

我的併發名單包裝:

public class ConcurrentList<T> : IList<T>, IDisposable 
{ 
    #region Fields 
    private readonly List<T> _list; 
    private readonly ReaderWriterLockSlim _lock; 
    #endregion 

    #region Constructors 
    public ConcurrentList() 
    { 
     this._lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); 
     this._list = new List<T>(); 
    } 

    public ConcurrentList(int capacity) 
    { 
     this._lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); 
     this._list = new List<T>(capacity); 
    } 

    public ConcurrentList(IEnumerable<T> items) 
    { 
     this._lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); 
     this._list = new List<T>(items); 
    } 
    #endregion 

    #region Methods 
    public void Add(T item) 
    { 
     try 
     { 
      this._lock.EnterWriteLock(); 
      this._list.Add(item); 
     } 
     finally 
     { 
      this._lock.ExitWriteLock(); 
     } 
    } 

    public void Insert(int index, T item) 
    { 
     try 
     { 
      this._lock.EnterWriteLock(); 
      this._list.Insert(index, item); 
     } 
     finally 
     { 
      this._lock.ExitWriteLock(); 
     } 
    } 

    public bool Remove(T item) 
    { 
     try 
     { 
      this._lock.EnterWriteLock(); 
      return this._list.Remove(item); 
     } 
     finally 
     { 
      this._lock.ExitWriteLock(); 
     } 
    } 

    public void RemoveAt(int index) 
    { 
     try 
     { 
      this._lock.EnterWriteLock(); 
      this._list.RemoveAt(index); 
     } 
     finally 
     { 
      this._lock.ExitWriteLock(); 
     } 
    } 

    public int IndexOf(T item) 
    { 
     try 
     { 
      this._lock.EnterReadLock(); 
      return this._list.IndexOf(item); 
     } 
     finally 
     { 
      this._lock.ExitReadLock(); 
     } 
    } 

    public void Clear() 
    { 
     try 
     { 
      this._lock.EnterWriteLock(); 
      this._list.Clear(); 
     } 
     finally 
     { 
      this._lock.ExitWriteLock(); 
     } 
    } 

    public bool Contains(T item) 
    { 
     try 
     { 
      this._lock.EnterReadLock(); 
      return this._list.Contains(item); 
     } 
     finally 
     { 
      this._lock.ExitReadLock(); 
     } 
    } 

    public void CopyTo(T[] array, int arrayIndex) 
    { 
     try 
     { 
      this._lock.EnterReadLock(); 
      this._list.CopyTo(array, arrayIndex); 
     } 
     finally 
     { 
      this._lock.ExitReadLock(); 
     } 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return new ConcurrentEnumerator<T>(this._list, this._lock); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return new ConcurrentEnumerator<T>(this._list, this._lock); 
    } 

    ~ConcurrentList() 
    { 
     this.Dispose(false); 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (disposing) 
      GC.SuppressFinalize(this); 

     this._lock.Dispose(); 
    } 
    #endregion 

    #region Properties 
    public T this[int index] 
    { 
     get 
     { 
      try 
      { 
       this._lock.EnterReadLock(); 
       return this._list[index]; 
      } 
      finally 
      { 
       this._lock.ExitReadLock(); 
      } 
     } 
     set 
     { 
      try 
      { 
       this._lock.EnterWriteLock(); 
       this._list[index] = value; 
      } 
      finally 
      { 
       this._lock.ExitWriteLock(); 
      } 
     } 
    } 

    public int Count 
    { 
     get 
     { 
      try 
      { 
       this._lock.EnterReadLock(); 
       return this._list.Count; 
      } 
      finally 
      { 
       this._lock.ExitReadLock(); 
      } 
     } 
    } 

    public bool IsReadOnly 
    { 
     get { return false; } 
    } 
    #endregion 
} 

public class ConcurrentEnumerator<T> : IEnumerator<T> 
{ 
    #region Fields 
    private readonly IEnumerator<T> _inner; 
    private readonly ReaderWriterLockSlim _lock; 
    #endregion 

    #region Constructor 
    public ConcurrentEnumerator(IEnumerable<T> inner, ReaderWriterLockSlim @lock) 
    { 
     this._lock = @lock; 
     this._lock.EnterReadLock(); 
     this._inner = inner.GetEnumerator(); 
    } 
    #endregion 

    #region Methods 
    public bool MoveNext() 
    { 
     return _inner.MoveNext(); 
    } 

    public void Reset() 
    { 
     _inner.Reset(); 
    } 

    public void Dispose() 
    { 
     this._lock.ExitReadLock(); 
    } 
    #endregion 

    #region Properties 
    public T Current 
    { 
     get { return _inner.Current; } 
    } 

    object IEnumerator.Current 
    { 
     get { return _inner.Current; } 
    } 
    #endregion 
} 

我該如何解決這個問題?我想使用這些數據並將其導出爲ex​​cel,但現在所有數據都混在一起了。

謝謝。

+0

我覺得很蠢。當然這不起作用,線程不會一個接一個地開始,所以它永遠不會同步我的列表。 我用了一個併發字典,並解決了這個問題。 對不起! – Rick

回答

1

對於ConcurrentList的包裝問題,不是實際的答案,而是因爲您只是從外部資源加載數據,您不需要爲這些數據執行並行執行。
使用async-await將以有效的方式進行 - 幾乎同時具有更易讀和可維護的代碼。

爲「主要」功能爲一對地址和郵政編碼檢索數據

private static HttpClient client1; 
private static HttpClient client2; 
private static HttpClient client3; 
// HttpClient should be initialized once for whole application life-cycle 
// Execute code below somewhere in your initialization 
client1 = new HttpClient(); 
client1.BaseAddress = new Uri("https://website1.com"); 
client2 = new HttpClient(); 
client2.BaseAddress = new Uri("https://website2.com"); 
client3 = new HttpClient(); 
client3.BaseAddress = new Uri("https://website3.com"); 


public async Task<IEnumerable<string>> GetDataAsync(string address, string postalCode) 
{ 
    var path = $"{address} {postalCode}"; // build proper path for request 
    var textFrom1 = await client1.GetAsync(path); // Base address already added; 

    if (textFrom1.Split(':', ',')[1] != "1") 
    { 
     return Enumerable.Repeat("empty", 3); 
    } 

    var textFrom2 = await client2.GetAsync(textFrom1.Split('"', '"')[11]); 
    var textFrom3 = await client3.GetAsync(textFrom2.Split('"', '"')[3]); 

    var allData = JsonConvert.DeserializeObject<List<RootObject>>(textFrom3); 

    var item = allData.First(); 
    return new[] 
    { 
     item.hoofdadres.geocodeerServiceZoekString, 
     item.gebruiksdoel, 
     item.begindatum.ToString() 
    }; 
} 

然後大家一起結合在一個收集

public async Task<IEnumerable<IEnumerable<string>> GetAll(
    IEnumerable<string> adresses, 
    IEnumerable<string> postalCodes) 
{ 
    // Start all tasks one by one without waiting for responses 
    var tasks = addresses.Zip(postalCodes, (addr, code) => GetData(addr, code)); 
    await Task.WhenAll(tasks); 

    return tasks.Select(task => task.Result).ToList(); 
} 

隨着做法上述要求創建異步方法/響應將以相同的速度並行處理,但不會擔心併發和結果同步,因爲所有操作都將在一個線程上執行。

+0

你是國王!這樣更快,看起來更乾淨。非常感謝你!! – Rick