Is there anything wrong with this code or can this be done more efficiently? In particular, i’m a little concerned about the code within parrallel.foreach firing/invoking a delegate. could this potentially cause any issues?
I ask because currently the consumers are unable to keep up with the items being produced in many cases, leading to memory issues.
public delegate void DataChangedDelegate(DataItem obj);
public class Consumer
{
public DataChangedDelegate OnCustomerChanged;
public DataChangedDelegate OnOrdersChanged;
private CancellationTokenSource cts;
private CancellationToken ct;
private BlockingCollection<DataItem> queue;
public Consumer(BlockingCollection<DataItem> queue) {
this.queue = queue;
Start();
}
private void Start() {
cts = new CancellationTokenSource();
ct = cts.Token;
Task.Factory.StartNew(() => DoWork(), ct);
}
private void DoWork() {
Parallel.ForEach(queue.GetConsumingPartitioner(), item => {
if (item.DataType == DataTypes.Customer) {
OnCustomerChanged(item);
} else if(item.DataType == DataTypes.Order) {
OnOrdersChanged(item);
}
});
}
}
In general terms, there’s nothing wrong with calling a delegate from within the
Parallel.ForEachmethod.However, it does make it more difficult to control thread safety, as the delegate will take on the requirements to handle all data synchronization correctly. This is mostly an issue since the main reason to use a delegate is to allow the “method” that you’re calling to be passed in, which means it’s being supplied externally.
This means, for example, that if a delegate happens to call code that tries to update a user interface, you may be in trouble, as it will get called from a background/ThreadPool thread.