In my case when I had the optimizations flag turned on it would not complete all the operations so there were measuring points missing in the final result so I simply turned the optimization flag off to fix the bug:
using System.Threading.Tasks;
Parallel.Invoke(
async () => await ProcessPartialArrayOperationAssets(operationAssets, 0, operationAssets.Count / 2,
operations, inspection1),
async () => await ProcessPartialArrayOperationAssets(operationAssets, operationAssets.Count / 2,
operationAssets.Count, operations, inspection1)
);
private async Task ProcessPartialArrayInspectionOperations(IList<InspectionOperation> operations,
int begin,
int end,
Inspection inspection,
InspectionAsset inspectionAsset)
{
await Task.Run(() =>
{
// create one new operation measuring point for each measuring point in the operation's equipment
int itemCounter = begin + 1;
for (int i = begin; i < end; i++)
{
lock (_thisLock)
{
InspectionOperation operation = operations[i];
int itemNumber = 1;
// get the asset
InspectionAsset operationAsset = operation.OperationAsset;
if (operationAsset != null)
{
// get the measuring points
string ABAPTrue = Abap.ABAP_TRUE;
lock (_thisLock)
{
IList<MeasuringPoint> measuringPoints = DbContext.MeasuringPoints.Where(x =>
x.AssetID == operationAsset.AssetID && x.InactiveFlag != ABAPTrue)
.ToList();
if (measuringPoints != null)
{
//Debug.WriteLine("measuringPoints.Count = " + measuringPoints.Count);
// create the operation measuring points
foreach (MeasuringPoint measuringPoint in measuringPoints)
{
OperationMeasuringPoint operationMeasuringPoint =
new OperationMeasuringPoint
{
InspectionID = inspection.InspectionID,
OperationNumber = operation.OperationNumber,
SubActivity = "",
RoutingNo = "",
ItemNumber = itemNumber.ToString("D4"),
// e.g. "0001", "0002" and so on
ItemCounter = itemCounter.ToString("D8"),
// e.g. "00000001", "00000002" and so on
MeasuringPointID = measuringPoint.MeasuringPointID,
MeasuringPointDescription = measuringPoint.Description,
Equipment = inspectionAsset.AssetID,
Category = "P"
};
DbContext.Entry(operationMeasuringPoint).State = EntityState.Added;
itemNumber++;
itemCounter++;
}
}
}
}
}
}
});
}
Thus I replaced the Parallel.Invoke call with this as well. FYI, this problem occurred using .NET Framework 4.7.
await ProcessPartialArrayOperationAssets(operationAssets, 0, operationAssets.Count, operations, inspection1);
UPDATE:
OK, I've found that I was able to re-enable the optimization flag and use Parallel.Invoke
if I remove the async Task
from the method signature:
private void ProcessPartialArrayInspectionOperations(IList<InspectionOperation> operations,
int begin,
int end,
Inspection inspection,
InspectionAsset inspectionAsset)
{
// create one new operation measuring point for each measuring point in the operation's equipment
int itemCounter = begin + 1;
for (int i = begin; i < end; i++)
{
InspectionOperation operation = operations[i];
int itemNumber = 1;
// get the asset
InspectionAsset operationAsset = operation.OperationAsset;
if (operationAsset != null)
{
// get the measuring points
string ABAPTrue = Abap.ABAP_TRUE;
lock (_thisLock)
{
IList<MeasuringPoint> measuringPoints = DbContext.MeasuringPoints.Where(x =>
x.AssetID == operationAsset.AssetID && x.InactiveFlag != ABAPTrue)
.ToList();
if (measuringPoints != null)
{
//Debug.WriteLine("measuringPoints.Count = " + measuringPoints.Count);
// create the operation measuring points
foreach (MeasuringPoint measuringPoint in measuringPoints)
{
OperationMeasuringPoint operationMeasuringPoint =
new OperationMeasuringPoint
{
InspectionID = inspection.InspectionID,
OperationNumber = operation.OperationNumber,
SubActivity = "",
RoutingNo = "",
ItemNumber = itemNumber.ToString("D4"),
// e.g. "0001", "0002" and so on
ItemCounter = itemCounter.ToString("D8"),
// e.g. "00000001", "00000002" and so on
MeasuringPointID = measuringPoint.MeasuringPointID,
MeasuringPointDescription = measuringPoint.Description,
Equipment = inspectionAsset.AssetID,
Category = "P"
};
DbContext.Entry(operationMeasuringPoint).State = EntityState.Added;
itemNumber++;
itemCounter++;
}
}
}
}
}
}
Parallel.Invoke(
() => ProcessPartialArrayInspectionOperations(operations, 0, operations.Count / 2,
inspection1, inspectionAsset),
() => ProcessPartialArrayInspectionOperations(operations, operations.Count / 2,
operations.Count, inspection1, inspectionAsset)
);
Alternatively, I think I could use Task.Run
for each and then a await Task.WhenAll(t1, t2, t3);
as explained here, but in this case I am not making explicit database calls so I don't think it applies to use Task.Run
instead of Parallel.Invoke
though this page does explain why my Parallel.Invoke was not completing: Parallel.Invoke does not wait for async methods to complete
For details, please see "Concurrency in C#" https://stephencleary.com/book/