0

我有这个问题,我似乎无法让它工作......

我的列表周围有一个包装器,以使其线程安全。但是,索引在我的 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 工作表。问题是返回的数据混淆了,所以迭代 0 不在 data[0] 中,而迭代 10 不在 data[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
}

我怎样才能解决这个问题?我想使用这些数据并将其导出到excel,但现在所有数据都混在一起了。

谢谢你。

4

1 回答 1

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();
}

使用上述方法,请求/响应将以与并行处理相同的速度进行处理,但无需担心并发和结果同步,因为所有这些都将在一个线程上执行。

于 2017-09-27T10:50:59.600 回答