Я хочу преобразовать некоторый существующий код в Parallel.Foreach, но я новичок в этом многопоточном программировании, и я пытался изменить код, но он показывает некоторые неожиданные поведения. Каждый раз что-то не так. Я читал о механизме locking, который нужно реализовать, но не знаю, как и где добавить операторы lock. Я также не уверен, является ли OrganizationRequestCollection потокобезопасным или нет.
public void ImportDataToCRM(List<Invoice> invoicesList, List<InvoiceLine> invoiceLinesList)
{
var organizationRequestCollection = new OrganizationRequestCollection();
foreach (Invoice invoice in invoicesList) //Need to convert this to Parallel.ForEach
{
Entity invoiceEntity = EntityMapper.GetEntity<Invoice>(invoice);
List<InvoiceLine> relatedLines = invoiceLinesList.Where(x => x.InternalId.Equals(invoice.InternalId) && x.DocumentNumber.Equals(invoice.DocumentNumber)).ToList();
if (relatedLines != null && relatedLines.Count > 0)
{
EntityCollection invoiceLineEntityCollection = new EntityCollection();
foreach (var invoiceLine in relatedLines ) //should this be converted to Parallel.Foreach??
{
Entity invoiceLineEntity = EntityMapper.GetEntity<InvoiceLine>(invoiceLine);
//Lock here ??
invoiceLineEntityCollection.Entities.Add(invoiceLineEntity);
}
//Lock here ??
invoiceEntity.RelatedEntities.Add(new Relationship("invoice_details"), invoiceLineEntityCollection);
}
//Lock here ??
organizationRequestCollection.Add(new CreateRequest()
{
Target = invoiceEntity
});
}
}
https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.organizationrequestcollection.aspx
https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.entitycollection.aspx
relatedLines != null будет никогда быть true.




1-й - вам не нужен вызов ToList() при назначении на List<InvoiceLine> relatedLines =
2-й - сложно вычесть только из кода, но если есть шанс, что
другой Entity invoiceEntity = EntityMapper.GetEntity<Invoice>(invoice); вернет одно и тожеinvoiceEntity, вам обязательно нужно заблокировать invoiceEntity.RelatedEntities.Add(..).
С другой стороны, если ваша программа гарантирует, что это никогда не произойдет, не используйте lock().
3-й - как насчет organizationRequestCollection: он инициализирован за пределами гипотетического параллельного-for, но использовал его внутри для Add(..), так что да, с этим дизайном вам нужен lock() там.
Чтобы избежать необходимости блокировать
organizationRequestCollection, рассмотрите возможность использованияinvoicesList.AsParallel().Select(z => { your code here, ultimately returning theCreateRequest).ToList(), а затем вызовитеorganizationRequestCollection.AddRange(если этот тип имеет этот метод).