C# Parallel.For not executing every step - c#

I have been working on a mock-up for an import service which currently runs in sequence. However my mock-up seems to exhibit a strange problem where by sometimes one or two items in the for loop aren't executed.
class Service
{
private Thread _worker;
private bool _stopping;
private CancellationTokenSource _cts;
private ParallelOptions _po;
private Repository _repository;
public void Start(Repository repository)
{
_repository = repository;
_cts = new CancellationTokenSource();
_po = new ParallelOptions {
CancellationToken = _cts.Token
};
_worker = new Thread(ProcessImport);
_worker.Start();
}
public void Stop()
{
_stopping = true;
_cts.Cancel();
if(_worker != null && _worker.IsAlive)
_worker.Join();
}
private void ProcessImport()
{
while (!_stopping)
{
var import = _repository.GetInProgressImport();
if (import == null)
{
Thread.Sleep(1000);
continue;
}
try
{
Parallel.For(0, 1000, _po, i => Work.DoWork(i, import, _cts.Token, _repository));
}
catch (OperationCanceledException)
{
// Unmark batch so it can be started again
batch = _repository.GetBatch(import.BatchId);
batch.Processing = false;
_repository.UpdateBatch(batch);
Console.WriteLine("Aborted import {0}", import.ImportId);
}
catch (Exception ex)
{
Console.WriteLine("Something went wrong: {0}", ex.Message);
}
}
}
}
class Work
{
public static void DoWork(int i, Import import, CancellationToken ct, Repository repository)
{
// Simulate doing some work
Thread.Sleep(100);
HandleAbort(ct);
Thread.Sleep(100);
HandleAbort(ct);
Thread.Sleep(100);
// Update the batch
var batch = repository.GetBatch(import.BatchId);
batch.Processed++;
if (batch.Processed == batch.Total)
{
batch.Finished = DateTime.Now;
batch.Processing = false;
}
repository.UpdateBatch(batch);
}
private static void HandleAbort(CancellationToken ct)
{
if (!ct.IsCancellationRequested)
return;
ct.ThrowIfCancellationRequested();
}
}
With this code, I often find that the batches are never complete and that batch.Processed = 999 or 998.
Can anyone shed any light on what I've done wrong.
Thanks in advance.
Edit:
To be clear about the repository/batch object - I believe in my current mock-up that it is threadsafe
class Repository
{
private ConcurrentBag<Batch> _batchData = new ConcurrentBag<Batch>();
private ConcurrentBag<Import> _importData = new ConcurrentBag<Import>();
public void CreateImport(Import import)
{
_importData.Add(import);
}
public Import GetInProgressImport()
{
var import = _importData
.Join(_batchData, i => i.BatchId, b => b.BatchId, (i, b) => new
{
Import = i,
Batch = b
})
.Where(j => j.Batch.Processed < j.Batch.Total && !j.Batch.Processing)
.OrderByDescending(j => j.Batch.Total - j.Batch.Processed)
.ThenBy(j => j.Batch.BatchId - j.Batch.BatchId)
.Select(j => j.Import)
.FirstOrDefault();
if (import == null)
return null;
// mark the batch as processing
var batch = GetBatch(import.BatchId);
batch.Processing = true;
UpdateBatch(batch);
return import;
}
public List<Import> ListImports()
{
return _importData.ToList();
}
public void CreateBatch(Batch batch)
{
_batchData.Add(batch);
}
public Batch GetBatch(Int64 batchId)
{
return _batchData.FirstOrDefault(b => b.BatchId == batchId);
}
public void UpdateBatch(Batch batch)
{
var batchData = _batchData.First(b => b.BatchId == batch.BatchId);
batchData.Total = batch.Total;
batchData.Processed = batch.Processed;
batchData.Started = batch.Started;
batchData.Finished = batch.Finished;
batchData.Processing = batch.Processing;
}
}
class Import
{
public Int64 ImportId { get; set; }
public Int64 BatchId { get; set; }
}
class Batch
{
public Int64 BatchId { get; set; }
public int Total { get; set; }
public int Processed { get; set; }
public DateTime Created { get; set; }
public DateTime Started { get; set; }
public DateTime Finished { get; set; }
public bool Processing { get; set; }
}
This is only a mock-up so there is no DB or other persistence behind my repository.
Also, I'm not competing my batch on the value of i, but rather the number of iterations of the loop (the work actually having been done) indicated by the Processed property of the batch object.
Thanks
Solution:
I had forgotten about the need synchronise the update of the batch. Should look like:
class Work
{
private static object _sync = new object();
public static void DoWork(int i, Import import, CancellationToken ct, Repository repository)
{
// Do work
Thread.Sleep(100);
HandleAbort(ct);
Thread.Sleep(100);
HandleAbort(ct);
Thread.Sleep(100);
lock (_sync)
{
// Update the batch
var batch = repository.GetBatch(import.BatchId);
batch.Processed++;
if (batch.Processed == batch.Total)
{
batch.Finished = DateTime.Now;
batch.Processing = false;
}
repository.UpdateBatch(batch);
}
}
private static void HandleAbort(CancellationToken ct)
{
if (!ct.IsCancellationRequested)
return;
ct.ThrowIfCancellationRequested();
}
}

Looks like lost updates on batch.Processed. Increments are not atomic. batch.Processed++; is racy. Use Interlocked.Increment.
It seems to me like you don't have a good understanding of threading right now. It's very dangerous to perform such elaborate threading without a good understanding. The mistakes you make are hard to test for but production will find them.

According to MSDN, the overloads of Parallel.For specify the second integer as toExclusive, meaning to goes up to but does not meet that value. In other words, 999 is the expected result, not 1000 - but note also that by starting at "0", your loop does execute 1,000 times.
From a glance, your code is parallel, so make sure you're not seeing the "999" call out of order from the "998" one - this is because by being executed in parallel, your code is inherently unordered, and can easily end up being very randomly rearranged. Also, read up on lock, as your code may be accessing values which it should be waiting for.

Related

Need help tweaking c# multi-threaded routine

I've created a windows service which runs a multi-threaded routine on a machine with 24 cores, 48 virtual, using Parallel.ForEach. This service, which has been running great in a production environment, bulk copies data into an SQL Server database. Currently it does this very well, around 6000 inserts per second, but I believe it can be tweaked. Below is part of the code I am using; there's an example of current functionality and proposed changes for tweaking. As can be seen from the code, currently a lock is taken for every call to Add, which I believe makes the Parallel.ForEach somewhat non-parallel. So I'm looking for a "fix"; and hoping my new method, also defined in the code, would do the trick.
public class MainLoop
{
public void DoWork()
{
var options = new ParallelOptions
{
MaxDegreeOfParallelism = System.Environment.ProcessorCount * 2
};
var workQueueManager = new ObjWorkQueueManager(queueSize: 1000);
// ignore the fact that this while loop would be a never ending loop,
// there's other logic not shown here that exits the loop!
while (true)
{
ICollection<object> work = GetWork();
Parallel.ForEach(work, options, (item) =>
{
workQueueManager.AddOLD(item);
});
}
}
private ICollection<object> GetWork()
{
// return list of work from some arbitrary source
throw new NotImplementedException();
}
}
public class ObjWorkQueueManager
{
private readonly int _queueSize;
private ObjDataReader _queueDataHandler;
private readonly object _sync;
public ObjWorkQueueManager(int queueSize)
{
_queueSize = queueSize;
_queueDataHandler = new ObjDataReader(queueSize);
_sync = new object();
}
// current Add method works great, but blocks with EVERY call
public void AddOLD(object value)
{
lock (_sync)
{
if (_queueDataHandler.Add(value) == _queueSize)
{
// create a new thread to handle copying the queued data to repository
Thread t = new Thread(SaveQueuedData);
t.Start(_queueDataHandler);
// start a new queue
_queueDataHandler = new ObjDataReader(_queueSize);
}
}
}
// hoping for a new Add method to work better by blocking only
// every nth call where n = _queueSize
public void AddNEW(object value)
{
int queued;
if ((queued = _queueDataHandler.Add(value)) >= _queueSize)
{
lock (_sync)
{
if (queued == _queueSize)
{
Thread t = new Thread(SaveQueuedData);
t.Start(_queueDataHandler);
}
}
}
else if (queued == 0)
{
lock (_sync)
{
_queueDataHandler = new ObjDataReader(_queueSize);
AddNEW(value);
}
}
}
// this method will Bulk Copy data into an SQL DB
private void SaveQueuedData(object o)
{
// do something with o as ObjDataReader
}
}
// implements IDataReader, Read method of IDataReader dequeues from _innerQueue
public class ObjDataReader
{
private readonly int _capacity;
private Queue<object> _innerQueue;
public ObjDataReader(int capacity)
{
_capacity = capacity;
_innerQueue = new Queue<object>(capacity);
}
public int Add(object value)
{
if (_innerQueue.Count < _capacity)
{
_innerQueue.Enqueue(value);
return _innerQueue.Count;
}
return 0;
}
}

Transaction scope similar functionality

I am looking to setup something very similar to transaction scope which creates a version on a service and will delete/commit at the end of scope. Every SQL statement ran inside the transaction scope internally looks at some connection pool / transaction storage to determine if its in the scope and reacts appropriately. The caller doesn't need to pass in the transaction to every call. I am looking for this functionality.
Here is a little more about it: https://blogs.msdn.microsoft.com/florinlazar/2005/04/19/transaction-current-and-ambient-transactions/
Here is the basic disposable class:
public sealed class VersionScope : IDisposable
{
private readonly GeodatabaseVersion _version;
private readonly VersionManager _versionManager;
public VersionScope(Configuration config)
{
_versionManager = new VersionManager(config);
_version = _versionManager.GenerateTempVersion();
_versionManager.Create(_version);
_versionManager.VerifyValidVersion(_version);
_versionManager.ServiceReconcilePull();
_versionManager.ReconcilePull(_version);
}
public void Dispose()
{
_versionManager.Delete(_version);
}
public void Complete()
{
_versionManager.ReconcilePush(_version);
}
}
I want the ability for all the code I've written thus far to not have any concept of being in a version. I just want to include a simple
Version = GetCurrentVersionWithinScope()
at the lowest level of the code.
What is the safest way of implementing something like this with little risk of using the wrong version if there are multiple instances in memory simultaneously running.
My very naive approach would be find if there is a unique identifier for a block of memory a process is running in. Then store the current working version to a global array or concurrent dictionary. Then in the code where I need the current version, I use its block of memory identifier and it maps to the version that was created.
Edit:
Example of usage:
using (var scope = new VersionScope(_config))
{
AddFeature(); // This has no concept of scope passed to it, and could error out forcing a dispose() without a complete()
scope.Complete();
}
The most straightforward approach would be to use ThreadStatic or ThreadLocal to store current version in thread local storage. That way multiple threads will not interfere with each other. For example suppose we version class:
public class Version {
public Version(int number) {
Number = number;
}
public int Number { get; }
public override string ToString() {
return "Version " + Number;
}
}
Then implementation of VersionScope can go like this:
public sealed class VersionScope : IDisposable {
private bool _isCompleted;
private bool _isDisposed;
// note ThreadStatic attribute
[ThreadStatic] private static Version _currentVersion;
public static Version CurrentVersion => _currentVersion;
public VersionScope(int version) {
_currentVersion = new Version(version);
}
public void Dispose() {
if (_isCompleted || _isDisposed)
return;
var v = _currentVersion;
if (v != null) {
DeleteVersion(v);
}
_currentVersion = null;
_isDisposed = true;
}
public void Complete() {
if (_isCompleted || _isDisposed)
return;
var v = _currentVersion;
if (v != null) {
PushVersion(v);
}
_currentVersion = null;
_isCompleted = true;
}
private void DeleteVersion(Version version) {
Console.WriteLine($"Version {version} deleted");
}
private void PushVersion(Version version) {
Console.WriteLine($"Version {version} pushed");
}
}
It will work, but it will not support nested scopes, which is not good, so to fix we need to store previous scope when starting new one, and restore it on Complete or Dispose:
public sealed class VersionScope : IDisposable {
private bool _isCompleted;
private bool _isDisposed;
private static readonly ThreadLocal<VersionChain> _versions = new ThreadLocal<VersionChain>();
public static Version CurrentVersion => _versions.Value?.Current;
public VersionScope(int version) {
var cur = _versions.Value;
// remember previous versions if any
_versions.Value = new VersionChain(new Version(version), cur);
}
public void Dispose() {
if (_isCompleted || _isDisposed)
return;
var cur = _versions.Value;
if (cur != null) {
DeleteVersion(cur.Current);
// restore previous
_versions.Value = cur.Previous;
}
_isDisposed = true;
}
public void Complete() {
if (_isCompleted || _isDisposed)
return;
var cur = _versions.Value;
if (cur != null) {
PushVersion(cur.Current);
// restore previous
_versions.Value = cur.Previous;
}
_isCompleted = true;
}
private void DeleteVersion(Version version) {
Console.WriteLine($"Version {version} deleted");
}
private void PushVersion(Version version) {
Console.WriteLine($"Version {version} pushed");
}
// just a class to store previous versions
private class VersionChain {
public VersionChain(Version current, VersionChain previous) {
Current = current;
Previous = previous;
}
public Version Current { get; }
public VersionChain Previous { get; }
}
}
That's already something you can work with. Sample usage (I use single thread, but if there were multiple threads doing this separately - they will not interfere with each other):
static void Main(string[] args) {
PrintCurrentVersion(); // no version
using (var s1 = new VersionScope(1)) {
PrintCurrentVersion(); // version 1
s1.Complete();
PrintCurrentVersion(); // no version, 1 is already completed
using (var s2 = new VersionScope(2)) {
using (var s3 = new VersionScope(3)) {
PrintCurrentVersion(); // version 3
} // version 3 deleted
PrintCurrentVersion(); // back to version 2
s2.Complete();
}
PrintCurrentVersion(); // no version, all completed or deleted
}
Console.ReadKey();
}
private static void PrintCurrentVersion() {
Console.WriteLine("Current version: " + VersionScope.CurrentVersion);
}
This however will not work when you are using async calls, because ThreadLocal is tied to a thread, but async method can span multiple threads. However, there is similar construct named AsyncLocal, which value will flow through asynchronous calls. So we can add constructor parameter to VersionScope indicating if we need async flow or not. Transaction scope works in a similar way - there is TransactionScopeAsyncFlowOption you pass into TransactionScope constructor indicating if it will flow through async calls.
Modified version looks like this:
public sealed class VersionScope : IDisposable {
private bool _isCompleted;
private bool _isDisposed;
private readonly bool _asyncFlow;
// thread local versions
private static readonly ThreadLocal<VersionChain> _tlVersions = new ThreadLocal<VersionChain>();
// async local versions
private static readonly AsyncLocal<VersionChain> _alVersions = new AsyncLocal<VersionChain>();
// to get current version, first check async local storage, then thread local
public static Version CurrentVersion => _alVersions.Value?.Current ?? _tlVersions.Value?.Current;
// helper method
private VersionChain CurrentVersionChain => _asyncFlow ? _alVersions.Value : _tlVersions.Value;
public VersionScope(int version, bool asyncFlow = false) {
_asyncFlow = asyncFlow;
var cur = CurrentVersionChain;
// remember previous versions if any
if (asyncFlow) {
_alVersions.Value = new VersionChain(new Version(version), cur);
}
else {
_tlVersions.Value = new VersionChain(new Version(version), cur);
}
}
public void Dispose() {
if (_isCompleted || _isDisposed)
return;
var cur = CurrentVersionChain;
if (cur != null) {
DeleteVersion(cur.Current);
// restore previous
if (_asyncFlow) {
_alVersions.Value = cur.Previous;
}
else {
_tlVersions.Value = cur.Previous;
}
}
_isDisposed = true;
}
public void Complete() {
if (_isCompleted || _isDisposed)
return;
var cur = CurrentVersionChain;
if (cur != null) {
PushVersion(cur.Current);
// restore previous
if (_asyncFlow) {
_alVersions.Value = cur.Previous;
}
else {
_tlVersions.Value = cur.Previous;
}
}
_isCompleted = true;
}
private void DeleteVersion(Version version) {
Console.WriteLine($"Version {version} deleted");
}
private void PushVersion(Version version) {
Console.WriteLine($"Version {version} pushed");
}
// just a class to store previous versions
private class VersionChain {
public VersionChain(Version current, VersionChain previous) {
Current = current;
Previous = previous;
}
public Version Current { get; }
public VersionChain Previous { get; }
}
}
Sample usage of scopes with async flow:
static void Main(string[] args) {
Test();
Console.ReadKey();
}
static async void Test() {
PrintCurrentVersion(); // no version
using (var s1 = new VersionScope(1, asyncFlow: true)) {
await Task.Delay(100);
PrintCurrentVersion(); // version 1
await Task.Delay(100);
s1.Complete();
await Task.Delay(100);
PrintCurrentVersion(); // no version, 1 is already completed
using (var s2 = new VersionScope(2, asyncFlow: true)) {
using (var s3 = new VersionScope(3, asyncFlow: true)) {
PrintCurrentVersion(); // version 3
} // version 3 deleted
await Task.Delay(100);
PrintCurrentVersion(); // back to version 2
s2.Complete();
}
await Task.Delay(100);
PrintCurrentVersion(); // no version, all completed or deleted
}
}
private static void PrintCurrentVersion() {
Console.WriteLine("Current version: " + VersionScope.CurrentVersion);
}
Use of IDisposable like this is somewhat questionable. (See Is it abusive to use IDisposable and "using" as a means for getting "scoped behavior" for exception safety?)
I, myself find it useful for some things. This is a pattern I use:
class LevelContext
{
private int _level;
public int CurrentLevel
{
get { return _level; }
set { _level = value < 0 ? 0 : value; }
}
public ILevel NewLevel(int depth = 1)
{
return new Level(this, depth);
}
/// <summary>
/// Provides an interface that calling code can use to handle level objects.
/// </summary>
public interface ILevel : IDisposable
{
LevelContext Owner { get; }
int Depth { get; }
void Close();
}
/// <summary>
/// Private class that provides an easy way to scope levels by allowing
/// them to participate in the "using" construct. Creation of a Level results in an
/// increase in owner's level, while disposal returns owner's level to what it was before.
/// </summary>
class Level : ILevel
{
public Level(LevelContext owner, int depth)
{
Owner = owner;
Depth = depth;
PreviousLevel = owner.CurrentLevel;
Owner.CurrentLevel += Depth;
}
public LevelContext Owner { get; private set; }
public int Depth { get; private set; }
public int PreviousLevel { get; private set; }
public void Close()
{
if (Owner != null)
{
Owner.CurrentLevel = PreviousLevel;
Owner = null;
}
}
void IDisposable.Dispose()
{
Close();
}
}
Then the calling code looks like this:
static void Main(string[] args)
{
var lc = new LevelContext();
Console.WriteLine(lc.CurrentLevel);
using (lc.NewLevel())
Console.WriteLine(lc.CurrentLevel);
Console.WriteLine(lc.CurrentLevel);
}
So in your case, you are correct - you need to create something that tracks the current version. That something should get updated when VersionScopes are created and disposed.

Ripple Effect: OutOfMemoryException

I have been trying to learn about Roslyn and see if it works for my needs.
In a very simple project I am trying to create a simple ‘Ripple Effect’, which is for each iteration causing a new assembly to be loaded and eventually after 500 iterations it crashes (OutOfMemoryException)
Is there a way to do this without causing it to explode?
class Program
{
static void Main(string[] args)
{
string code = #"
IEnumerable<double> combined = A.Concat(B);
return combined.Average();
";
Globals<double> globals = new Globals<double>()
{
A = new double[] { 1, 2, 3, 4, 5 },
B = new double[] { 1, 2, 3, 4, 5 },
};
ScriptOptions options = ScriptOptions.Default;
Assembly systemCore = typeof(Enumerable).Assembly;
options = options.AddReferences(systemCore);
options = options.AddImports("System");
options = options.AddImports("System.Collections.Generic");
options = options.AddImports("System.Linq");
var ra = CSharpScript.RunAsync(code, options, globals).Result;
for (int i = 0; i < 1000; i++)
{
ra = ra.ContinueWithAsync(code).Result;
}
}
}
public class Globals<T>
{
public IEnumerable<T> A;
public IEnumerable<T> B;
}
Exception Image
Everytime you use CSharpScript.Run or Evaluate method you are actually loading a new script (a .dll) which happens to be quite large. In order to avoid this you need te cache the script that you are executing by doing so:
_script = CSharpScript.Create<TR>(code, opts, typeof(Globals<T>)); // Other options may be needed here
Having _script cached you can now execute it by:
_script.RunAsync(new Globals<T> {A = a, B = b}); // The script will compile here in the first execution
If you have a few scripts to load with your application each time, this is the easiest thing to do. However a better solution is to use a separate AppDomain and load the script isolated. Here is one way of doing it:
Create a script executor proxy as MarshalByRefObject:
public class ScriptExecutor<TP, TR> : CrossAppDomainObject, IScriptExecutor<TP, TR>
{
private readonly Script<TR> _script;
private int _currentClients;
public DateTime TimeStamp { get; }
public int CurrentClients => _currentClients;
public string Script => _script.Code;
public ScriptExecutor(string script, DateTime? timestamp = null, bool eagerCompile = false)
{
if (string.IsNullOrWhiteSpace(script))
throw new ArgumentNullException(nameof(script));
var opts = ScriptOptions.Default.AddImports("System");
_script = CSharpScript.Create<TR>(script, opts, typeof(Host<TP>)); // Other options may be needed here
if (eagerCompile)
{
var diags = _script.Compile();
Diagnostic firstError;
if ((firstError = diags.FirstOrDefault(d => d.Severity == DiagnosticSeverity.Error)) != null)
{
throw new ArgumentException($"Provided script can't compile: {firstError.GetMessage()}");
}
}
if (timestamp == null)
timestamp = DateTime.UtcNow;
TimeStamp = timestamp.Value;
}
public void Execute(TP parameters, RemoteCompletionSource<TR> completionSource)
{
Interlocked.Increment(ref _currentClients);
_script.RunAsync(new Host<TP> {Args = parameters}).ContinueWith(t =>
{
if (t.IsFaulted && t.Exception != null)
{
completionSource.SetException(t.Exception.InnerExceptions.ToArray());
Interlocked.Decrement(ref _currentClients);
}
else if (t.IsCanceled)
{
completionSource.SetCanceled();
Interlocked.Decrement(ref _currentClients);
}
else
{
completionSource.SetResult(t.Result.ReturnValue);
Interlocked.Decrement(ref _currentClients);
}
});
}
}
public class Host<T>
{
public T Args { get; set; }
}
Create a proxy object to share data between script execution app domain and the main domain:
public class RemoteCompletionSource<T> : CrossAppDomainObject
{
private readonly TaskCompletionSource<T> _tcs = new TaskCompletionSource<T>();
public void SetResult(T result) { _tcs.SetResult(result); }
public void SetException(Exception[] exception) { _tcs.SetException(exception); }
public void SetCanceled() { _tcs.SetCanceled(); }
public Task<T> Task => _tcs.Task;
}
Create this helper abstract type that all the other remote ones need to inherit from:
public abstract class CrossAppDomainObject : MarshalByRefObject, IDisposable
{
private bool _disposed;
/// <summary>
/// Gets an enumeration of nested <see cref="MarshalByRefObject"/> objects.
/// </summary>
protected virtual IEnumerable<MarshalByRefObject> NestedMarshalByRefObjects
{
get { yield break; }
}
~CrossAppDomainObject()
{
Dispose(false);
}
/// <summary>
/// Disconnects the remoting channel(s) of this object and all nested objects.
/// </summary>
private void Disconnect()
{
RemotingServices.Disconnect(this);
foreach (var tmp in NestedMarshalByRefObjects)
RemotingServices.Disconnect(tmp);
}
public sealed override object InitializeLifetimeService()
{
//
// Returning null designates an infinite non-expiring lease.
// We must therefore ensure that RemotingServices.Disconnect() is called when
// it's no longer needed otherwise there will be a memory leak.
//
return null;
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
Disconnect();
_disposed = true;
}
}
Here is how we use it:
public static IScriptExecutor<T, R> CreateExecutor<T, R>(AppDomain appDomain, string script)
{
var t = typeof(ScriptExecutor<T, R>);
var executor = (ScriptExecutor<T, R>)appDomain.CreateInstanceAndUnwrap(t.Assembly.FullName, t.FullName, false, BindingFlags.CreateInstance, null,
new object[] {script, null, true}, CultureInfo.CurrentCulture, null);
return executor;
}
public static AppDomain CreateSandbox()
{
var setup = new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase };
var appDomain = AppDomain.CreateDomain("Sandbox", null, setup, AppDomain.CurrentDomain.PermissionSet);
return appDomain;
}
string script = #"int Square(int number) {
return number*number;
}
Square(Args)";
var domain = CreateSandbox();
var executor = CreateExecutor<int, int>(domain, script);
using (var src = new RemoteCompletionSource<int>())
{
executor.Execute(5, src);
Console.WriteLine($"{src.Task.Result}");
}
Note the usage of RemoteCompletionSource within a using block. If you forget to dispose it you will have memory leaks because instances of this object on the other domain (not the caller) will never get GCed.
Disclaimer: I took the idea of RemoteCompletionSource from
here, also the idea for the CrossAppDomainObject from public domain.

How to buffer a burst of events into fewer resulting actions

I want to reduce multiple events into a single delayed action. After some trigger occurs I expect some more similar triggers to come, but I prefer not to repeat the resulting delayed action. The action waits, to give a chance of completion to the burst.
The question: How can I do it in an elegant reusable way?
Till now I used a property to flag the event and trigger a delayed action like below:
public void SomeMethod()
{
SomeFlag = true; //this will intentionally return to the caller before completing the resulting buffered actions.
}
private bool someFlag;
public bool SomeFlag
{
get { return someFlag; }
set
{
if (someFlag != value)
{
someFlag = value;
if (value)
SomeDelayedMethod(5000);
}
}
}
public async void SomeDelayedMethod(int delay)
{
//some bufferred work.
await Task.Delay(delay);
SomeFlag = false;
}
below is a shorter way, but still not generic or reusable... I want something concise that packages the actions and the flag, and keeps the functionality (returning to the caller before execution is complete (like today)). I also need to be able to pass an object reference to this action)
public void SerializeAccountsToConfig()
{
if (!alreadyFlagged)
{
alreadyFlagged = true;
SerializeDelayed(5000, Serialize);
}
}
public async void SerializeDelayed(int delay, Action whatToDo)
{
await Task.Delay(delay);
whatToDo();
}
private bool alreadyFlagged;
private void Serialize()
{
//some buferred work.
//string json = JsonConvert.SerializeObject(Accounts, Formatting.Indented);
//Settings1.Default.Accounts = json;
//Settings1.Default.Save();
alreadyFlagged = false;
}
Here's a thread-safe and reusable solution.
You can create an instance of DelayedSingleAction, and in the constructor you pass the action that you want to have performed. I believe this is thread safe, though there is a tiny risk that it will restart the timer just before commencing the action, but I think that risk would exist no matter what the solution is.
public class DelayedSingleAction
{
private readonly Action _action;
private readonly long _millisecondsDelay;
private long _syncValue = 1;
public DelayedSingleAction(Action action, long millisecondsDelay)
{
_action = action;
_millisecondsDelay = millisecondsDelay;
}
private Task _waitingTask = null;
private void DoActionAndClearTask(Task _)
{
Interlocked.Exchange(ref _syncValue, 1);
_action();
}
public void PerformAction()
{
if (Interlocked.Exchange(ref _syncValue, 0) == 1)
{
_waitingTask = Task.Delay(TimeSpan.FromMilliseconds(_millisecondsDelay))
.ContinueWith(DoActionAndClearTask);
}
}
public Task Complete()
{
return _waitingTask ?? Task.FromResult(0);
}
}
See this dotnetfiddle for an example which invokes one action continuously from multiple threads.
https://dotnetfiddle.net/el14wZ
Since you're interested in RX here simple console app sample:
static void Main(string[] args)
{
// event source
var burstEvents = Observable.Interval(TimeSpan.FromMilliseconds(50));
var subscription = burstEvents
.Buffer(TimeSpan.FromSeconds(3)) // collect events 3 seconds
//.Buffer(50) // or collect 50 events
.Subscribe(events =>
{
//Console.WriteLine(events.First()); // take only first event
// or process event collection
foreach (var e in events)
Console.Write(e + " ");
Console.WriteLine();
});
Console.ReadLine();
return;
}
Based on the solution proposed by Andrew, here is a more generic solution.
Declaration and instance creation of the delayed action:
public DelayedSingleAction<Account> SendMailD;
Create the instance inside a function or in the constructor (this can be a collection of such actions each working on a different object):
SendMailD = new DelayedSingleAction<Account>(SendMail, AccountRef, 5000);
repeatedly call this action
SendMailD.PerformAction();
Send mail is the action you will "burst control". Its signature matches :
public int SendMail(Account A)
{}
Here is the updated class
public class DelayedSingleAction<T>
{
private readonly Func<T, int> actionOnObj;
private T tInstance;
private readonly long millisecondsDelay;
private long _syncValue = 1;
public DelayedSingleAction(Func<T, int> ActionOnObj, T TInstance, long MillisecondsDelay)
{
actionOnObj = ActionOnObj;
tInstance = TInstance;
millisecondsDelay = MillisecondsDelay;
}
private Task _waitingTask = null;
private void DoActionAndClearTask(Task _)
{
Console.WriteLine(string.Format("{0:h:mm:ss.fff} DelayedSingleAction Resetting SyncObject: Thread {1} for {2}", DateTime.Now, System.Threading.Thread.CurrentThread.ManagedThreadId, tInstance));
Interlocked.Exchange(ref _syncValue, 1);
actionOnObj(tInstance);
}
public void PerformAction()
{
if (Interlocked.Exchange(ref _syncValue, 0) == 1)
{
Console.WriteLine(string.Format("{0:h:mm:ss.fff} DelayedSingleAction Starting the timer: Thread {1} for {2}", DateTime.Now, System.Threading.Thread.CurrentThread.ManagedThreadId, tInstance));
_waitingTask = Task.Delay(TimeSpan.FromMilliseconds(millisecondsDelay)).ContinueWith(DoActionAndClearTask);
}
}
public Task Complete()
{
return _waitingTask ?? Task.FromResult(0);
}
}

Multithreading BlockingCollection Alternatives to GetConsumingEnumerable() Producer-Consumer

I have a situation where I have multiple producers and multiple consumers. The producers enters a job into a queue. I chose the BlockingCollection and it works great since I need the consumers to wait for a job to be found. However, if I use the GetConsumingEnumerable() feature the order of the items in the collection change... this is not what I need.
It even says in MSDN http://msdn.microsoft.com/en-us/library/dd287186.aspx
that it does not preserve the order of the items.
Does anyone know an alternative for this situation?
I see that the Take method is available but does it also provide a 'wait' condition for the consumer threads?
It says http://msdn.microsoft.com/en-us/library/dd287085.aspx
'A call to Take may block until an item is available to be removed.' Is it better to use TryTake? I really need the thread to wait and keep checking for a job.
Take blocks the thread till something comes available.
TryTake as the name implies tries to do so but returns a bool if it fails or succeeds.
Allowing for more flex using it:
while(goingOn){
if( q.TryTake(out var){
Process(var)
}
else{
DoSomething_Usefull_OrNotUseFull_OrEvenSleep();
}
}
instead of
while(goingOn){
if( var x = q.Take(){
//w'll wait till this ever will happen and then we:
Process(var)
}
}
My votes are for TryTake :-)
EXAMPLE:
public class ProducerConsumer<T> {
public struct Message {
public T Data;
}
private readonly ThreadRunner _producer;
private readonly ThreadRunner _consumer;
public ProducerConsumer(Func<T> produce, Action<T> consume) {
var q = new BlockingCollection<Message>();
_producer = new Producer(produce,q);
_consumer = new Consumer(consume,q);
}
public void Start() {
_producer.Run();
_consumer.Run();
}
public void Stop() {
_producer.Stop();
_consumer.Stop();
}
private class Producer : ThreadRunner {
public Producer(Func<T> produce, BlockingCollection<Message> q) : base(q) {
_produce = produce;
}
private readonly Func<T> _produce;
public override void Worker() {
try {
while (KeepRunning) {
var item = _produce();
MessageQ.TryAdd(new Message{Data = item});
}
}
catch (ThreadInterruptedException) {
WasInterrupted = true;
}
}
}
public abstract class ThreadRunner {
protected readonly BlockingCollection<Message> MessageQ;
protected ThreadRunner(BlockingCollection<Message> q) {
MessageQ = q;
}
protected Thread Runner;
protected bool KeepRunning = true;
public bool WasInterrupted;
public abstract void Worker();
public void Run() {
Runner = new Thread(Worker);
Runner.Start();
}
public void Stop() {
KeepRunning = false;
Runner.Interrupt();
Runner.Join();
}
}
class Consumer : ThreadRunner {
private readonly Action<T> _consume;
public Consumer(Action<T> consume,BlockingCollection<Message> q) : base(q) {
_consume = consume;
}
public override void Worker() {
try {
while (KeepRunning) {
Message message;
if (MessageQ.TryTake(out message, TimeSpan.FromMilliseconds(100))) {
_consume(message.Data);
}
else {
//There's nothing in the Q so I have some spare time...
//Excellent moment to update my statisics or update some history to logfiles
//for now we sleep:
Thread.Sleep(TimeSpan.FromMilliseconds(100));
}
}
}
catch (ThreadInterruptedException) {
WasInterrupted = true;
}
}
}
}
}
USAGE:
[Fact]
public void ConsumerShouldConsume() {
var produced = 0;
var consumed = 0;
Func<int> produce = () => {
Thread.Sleep(TimeSpan.FromMilliseconds(100));
produced++;
return new Random(2).Next(1000);
};
Action<int> consume = c => { consumed++; };
var t = new ProducerConsumer<int>(produce, consume);
t.Start();
Thread.Sleep(TimeSpan.FromSeconds(5));
t.Stop();
Assert.InRange(produced,40,60);
Assert.InRange(consumed, 40, 60);
}

Categories