Synchronous Task Execution in C# - c#

I have a method in a Singleton class which will be called from different threads. But I need to execute them one by one. like
The method ImageUtil.Instance.LoadImage(imageID) will be called from multiple threads. But I want to load image one by one. So at a time only one image will load.
public class ImageUtil
{
#region Singleton Implementation
private ImageUtil()
{
taskList = new List<Task<object>>();
}
public static ImageUtil Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as before field init
static Nested()
{
}
internal static readonly ImageUtil instance = new ImageUtil();
}
#endregion
Queue<Task<Object>> taskList;
bool isProcessing;
public async Task<Object> LoadImage(String imageID)
{
//Here what I need to put to execute "return await LoadImageInternal(imageID);"
//one by one. So that if one image is loading and mean time some other thread
//calls this method then the last thread have to wait until current loading finish.
}
private async Task<Object> LoadImageInternal(String imageID)
{
//Business Logic for image retrieval.
}
}

SemaphoreSlim has a WaitAsync method that allows you to enforce critical sections asynchronously:
private readonly SemaphoreSlim loadSemaphore = new SemaphoreSlim(1, 1);
public async Task<Object> LoadImage(String imageID)
{
await loadSemaphore.WaitAsync();
try
{
return await LoadImageInternal(imageID);
}
finally
{
loadSemaphore.Release();
}
}
This pattern is presented in Stephen Toub's article.

List<Task<Object>> taskList;
private static readonly object _syncLock = new object();
public Task<Object> LoadImage(String imageID)
{
return Task<Object>.Factory.StartNew(() =>
{
lock (_syncLock)
{
return LoadImageInternal(imageID).Result;
}
});
}
private async Task<Object> LoadImageInternal(String imageID)
{
//Business Logic for image retrieval.
}
That should accomplish what you asked for, but personally I would tackle this differently with a long-running task and a Queue of some sort. The long running task would simply loop forever and check the Queue for new items and then execute them one at a time, this would prevent a lot of unnecessary thread context switching.

//This is how you can implement it using yield return to return one image at a time
public IEnumerable<Task<string>> GetPerItemAsync(IEnumerable<string> images)
{
foreach (var image in images)
{
yield return LoadImage(image);
}
}
public static Task<string> LoadImage(string image)
{
var result = image.Trim(); // Some complex business logic on the image, NOT
return new Task<string>(() => result);
}
//Call your method in you client
//First, get your images from the data source
var listOfimages = Context.Images.ToList();
//Get results
var result = GetPerItemAsync(listOfimages).FirstOrDefault();

Related

Get method name and parameters when it's invoked through a task queue

I have a simple task queue that allows one task to execute at a time:
public class TaskQueue
{
public SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
{
await semaphore.WaitAsync();
try
{
return await taskGenerator();
}
finally
{
semaphore.Release();
}
}
public async Task Enqueue(Func<Task> taskGenerator)
{
await semaphore.WaitAsync();
try
{
await taskGenerator();
}
finally
{
semaphore.Release();
}
}
}
And I would queue a task in there like so:
private async Task SaveData()
{
//some code
await taskQueue.Enqueue(async () => { printed = await pm.Print(Template); });
//some code
}
Now what I would like to do is inside the Enqueue method add a log that will contain the info $Print was called with parameter {Template}. How can I get the name of the method executed and it's parameters?
I know I can do [CallerMemberName] string caller = "" to get info that the call was made inside SaveData, but is there an attribute or something to log the info I want?
this is possible (expression trees, etc), but it is incredibly inefficient; perhaps a better approach is to enqueue an object instead, i.e.
abstract class ThingToDo {
public abstract Task DoTheThingAsync();
}
and make your queue a queue of ThingToDo instead of Func<Task<T>>, then you can have things like:
sealed class PrintThing : ThingToDo {
private readonly int x;
private readonly string y;
private readonly string caller;
public PrintThing(int x, string y, [CallerMemberName] string caller = null) {
this.x = x;
this.y = y;
this.caller = caller;
}
public override Task DoTheThingAsync() {...}
public override ToString() => $"{nameof(PrintThing)}, x={x}, y={y} from {caller}";
}
and now you can output the task trivially.
In reality, this isn't all that different to what the compiler would generate anyway for a lambda/anonymous method with captured variables.
I would add the log into the different methods. That way you can also specialize the log messages produced by each method.

Close task before run again

I working on real-time search. At this moment on property setter which is bounded to edit text, I call a method which calls API and then fills the list with the result it looks like this:
private string searchPhrase;
public string SearchPhrase
{
get => searchPhrase;
set
{
SetProperty(ref searchPhrase, value);
RunOnMainThread(SearchResult.Clear);
isAllFriends = false;
currentPage = 0;
RunInAsync(LoadData);
}
}
private async Task LoadData()
{
var response = await connectionRepository.GetConnections(currentPage,
pageSize, searchPhrase);
foreach (UserConnection uc in response)
{
if (uc.Type != UserConnection.TypeEnum.Awaiting)
{
RunOnMainThread(() =>
SearchResult.Add(new ConnectionUser(uc)));
}
}
}
But this way is totally useless because of it totally mashup list of a result if a text is entering quickly. So to prevent this I want to run this method async in a property but if a property is changed again I want to kill the previous Task and star it again. How can I achieve this?
Some informations from this thread:
create a CancellationTokenSource
var ctc = new CancellationTokenSource();
create a method doing the async work
private static Task ExecuteLongCancellableMethod(CancellationToken token)
{
return Task.Run(() =>
{
token.ThrowIfCancellationRequested();
// more code here
// check again if this task is canceled
token.ThrowIfCancellationRequested();
// more code
}
}
It is important to have this checks for cancel in the code.
Execute the function:
var cancellable = ExecuteLongCancellableMethod(ctc.Token);
To stop the long running execution use
ctc.Cancel();
For further details please consult the linked thread.
This question can be answered in many different ways. However IMO I would look at creating a class that
Delays itself automatically for X (ms) before performing the seach
Has the ability to be cancelled at any time as the search request changes.
Realistically this will change your code design, and should encapsulate the logic for both 1 & 2 in a separate class.
My initial thoughts are (and none of this is tested and mostly pseudo code).
class ConnectionSearch
{
public ConnectionSearch(string phrase, Action<object> addAction)
{
_searchPhrase = phrase;
_addAction = addAction;
_cancelSource = new CancellationTokenSource();
}
readonly string _searchPhrase = null;
readonly Action<object> _addAction;
readonly CancellationTokenSource _cancelSource;
public void Cancel()
{
_cancelSource?.Cancel();
}
public async void PerformSearch()
{
await Task.Delay(300); //await 300ms between keystrokes
if (_cancelSource.IsCancellationRequested)
return;
//continue your code keep checking for
//loop your dataset
//call _addAction?.Invoke(uc);
}
}
This is basic, really just encapsulates the logic for both points 1 & 2, you will need to adapt the code to do the search.
Next you could change your property to cancel a previous running instance, and then start another instance immediatly after something like below.
ConnectionSearch connectionSearch;
string searchPhrase;
public string SearchPhrase
{
get => searchPhrase;
set
{
//do your setter work
if(connectionSearch != null)
{
connectionSearch.Cancel();
}
connectionSearch = new ConnectionSearch(value, addConnectionUser);
connectionSearch.PerformSearch();
}
}
void addConnectionUser(object uc)
{
//pperform your add logic..
}
The code is pretty straight forward, however you will see in the setter is simply cancelling an existing request and then creating a new request. You could put some disposal cleanup logic in place but this should get you started.
You can implement some sort of debouncer which will encapsulate the logics of task result debouncing, i.e. it will assure if you run many tasks, then only the latest task result will be used:
public class TaskDebouncer<TResult>
{
public delegate void TaskDebouncerHandler(TResult result, object sender);
public event TaskDebouncerHandler OnCompleted;
public event TaskDebouncerHandler OnDebounced;
private Task _lastTask;
private object _lock = new object();
public void Run(Task<TResult> task)
{
lock (_lock)
{
_lastTask = task;
}
task.ContinueWith(t =>
{
if (t.IsFaulted)
throw t.Exception;
lock (_lock)
{
if (_lastTask == task)
{
OnCompleted?.Invoke(t.Result, this);
}
else
{
OnDebounced?.Invoke(t.Result, this);
}
}
});
}
public async Task WaitLast()
{
await _lastTask;
}
}
Then, you can just do:
private readonly TaskDebouncer<Connections[]> _connectionsDebouncer = new TaskDebouncer<Connections[]>();
public ClassName()
{
_connectionsDebouncer.OnCompleted += OnConnectionUpdate;
}
public void OnConnectionUpdate(Connections[] connections, object sender)
{
RunOnMainThread(SearchResult.Clear);
isAllFriends = false;
currentPage = 0;
foreach (var conn in connections)
RunOnMainThread(() => SearchResult.Add(new ConnectionUser(conn)));
}
private string searchPhrase;
public string SearchPhrase
{
get => searchPhrase;
set
{
SetProperty(ref searchPhrase, value);
_connectionsDebouncer.Add(RunInAsync(LoadData));
}
}
private async Task<Connection[]> LoadData()
{
return await connectionRepository
.GetConnections(currentPage, pageSize, searchPhrase)
.Where(conn => conn.Type != UserConnection.TypeEnum.Awaiting)
.ToArray();
}
It is not pretty clear what RunInAsync and RunOnMainThread methods are.
I guess, you don't actually need them.

Locking according to Id in async method

I have MVC application in which action methods must be executed on certain order. Recently, I am having some strange issues and I suppose that it is due to the fact that I do not do any thread synchronization. I have barely worked with multithreading and I don't know much about it. I tried to implement some kind of locking where I have to lock according to Id. So I implemented class like below to get required lock objects.
public class ReportLockProvider
: IReportLockProvider
{
readonly ConcurrentDictionary<long, object> lockDictionary
= new ConcurrentDictionary<long, object>();
public object ProvideLockObject(long reportId)
{
return lockDictionary.GetOrAdd(reportId, new object());
}
}
I tried to use this as below:
ReportLockProvider lockProvider = new ReportLockProvider();
public async ActionResult MyAction(long reportId)
{
lock(lockProvider.ProvideLockObject(reportId))
{
// Some operations
await Something();
// Some operation
}
}
I hoped that it would work, but it event didn't compiled because I have used await inside lock body. I have searched a bit and came across to SemaphoreSlim in this answer. Now, the problem is that I have to get lock object according to Id. How can I do this? Is it OK to create multiple SemaphoreSlim objects? Is it OK if I modify code like below :
public class ReportLockProvider
: IReportLockProvider
{
readonly ConcurrentDictionary<long, SemaphoreSlim> lockDictionary
= new ConcurrentDictionary<long, SemaphoreSlim>();
public SemaphoreSlim ProvideLockObject(long reportId)
{
return lockDictionary.GetOrAdd(reportId, new SemaphoreSlim(1, 1));
}
}
public async ActionResult MyAction(long reportId)
{
var lockObject = ReportLockProvider.ProvideLockObject(reportId);
await lockObject.WaitAsync();
try
{
// Some operations
await Something();
// Some operation
}
finally
{
lockObject.Release();
}
}
The other question is that, can I use SemaphoreSlim in non-async methods? Is there any better option?
I think you are missing a static keyword in front of your lockDictionary, but it depends on how you instanciate the provider.
Here is a sample with a little change code I cooked up in LinqPad:
async Task Main()
{
ReportLockProvider reportLockProvider = new ReportLockProvider();
List<Task> tasks = new List<Task>(10);
for (long i = 1; i <= 5; i++) {
var local = i;
tasks.Add(Task.Run(() => Enter(local) ));
tasks.Add(Task.Run(() => Enter(local) ));
}
async Task Enter(long id)
{
Console.WriteLine(id + " waiting to enter");
await reportLockProvider.WaitAsync(id);
Console.WriteLine(id + " entered!");
Thread.Sleep(1000 * (int)id);
Console.WriteLine(id + " releasing");
reportLockProvider.Release(id);
}
await Task.WhenAll(tasks.ToArray());
}
public class ReportLockProvider
{
static readonly ConcurrentDictionary<long, SemaphoreSlim> lockDictionary = new ConcurrentDictionary<long, SemaphoreSlim>();
public async Task WaitAsync(long reportId)
{
await lockDictionary.GetOrAdd(reportId, new SemaphoreSlim(1, 1)).WaitAsync();
}
public void Release(long reportId)
{
SemaphoreSlim semaphore;
if (lockDictionary.TryGetValue(reportId, out semaphore))
{
semaphore.Release();
}
}
}

How to best prevent running async method again before it completes?

I've got this pattern for preventing calling into an async method before it has had a chance to complete previously.
My solution involving needing a flag, and then needing to lock around the flag, feels pretty verbose. Is there a more natural way of achieving this?
public class MyClass
{
private object SyncIsFooRunning = new object();
private bool IsFooRunning { get; set;}
public async Task FooAsync()
{
try
{
lock(SyncIsFooRunning)
{
if(IsFooRunning)
return;
IsFooRunning = true;
}
// Use a semaphore to enforce maximum number of Tasks which are able to run concurrently.
var semaphoreSlim = new SemaphoreSlim(5);
var trackedTasks = new List<Task>();
for(int i = 0; i < 100; i++)
{
await semaphoreSlim.WaitAsync();
trackedTasks.Add(Task.Run(() =>
{
// DoTask();
semaphoreSlim.Release();
}));
}
// Using await makes try/catch/finally possible.
await Task.WhenAll(trackedTasks);
}
finally
{
lock(SyncIsFooRunning)
{
IsFooRunning = false;
}
}
}
}
As noted in the comments, you can use Interlocked.CompareExchange() if you prefer:
public class MyClass
{
private int _flag;
public async Task FooAsync()
{
try
{
if (Interlocked.CompareExchange(ref _flag, 1, 0) == 1)
{
return;
}
// do stuff
}
finally
{
Interlocked.Exchange(ref _flag, 0);
}
}
}
That said, I think it's overkill. Nothing wrong with using lock in this type of scenario, especially if you don't expect a lot of contention on the method. What I do think would be better is to wrap the method so that the caller can always await on the result, whether a new asynchronous operation was started or not:
public class MyClass
{
private readonly object _lock = new object();
private Task _task;
public Task FooAsync()
{
lock (_lock)
{
return _task != null ? _task : (_task = FooAsyncImpl());
}
}
public async Task FooAsyncImpl()
{
try
{
// do async stuff
}
finally
{
lock (_lock) _task = null;
}
}
}
Finally, in the comments, you say this:
Seems a bit odd that all the return types are still valid for Task?
Not clear to me what you mean by that. In your method, the only valid return types would be void and Task. If your return statement(s) returned an actual value, you'd have to use Task<T> where T is the type returned by the return statement(s).

Threading With List Property

public static class People
{
List<string> names {get; set;}
}
public class Threading
{
public static async Task DoSomething()
{
var t1 = new Task1("bob");
var t2 = new Task1("erin");
await Task.WhenAll(t1,t2);
}
private static async Task Task1(string name)
{
await Task.Run(() =>
{
if(People.names == null) People.names = new List<string>();
Peoples.names.Add(name);
}
}
}
Is that dangerous to initialize a list within a thread? Is it possible that both threads could initialize the list and remove one of the names?
So I was thinking of three options:
Leave it like this since it is simple - only if it is safe though
Do same code but use a concurrentBag - I know thread safe but is initialize safe
Using [DataMember(EmitDefaultValue = new List())] and then just do .Add in Task1 and not worry about initializing. But the only con to this is sometimes the list wont need to be used at all and it seems like a waste to initialize it everytime.
Okay so what I figured worked best for my case was I used a lock statement.
public class Class1
{
private static Object thisLock = new Object();
private static async Task Task1(string name)
{
await Task.Run(() =>
{
AddToList(name);
}
}
private static AddToList(string name)
{
lock(thisLock)
{
if(People.names == null) People.names = new List<string>();
People.names.Add(name);
}
}
}
public static class People
{
public static List<string> names {get; set;}
}
for a simple case like this the easiest way to get thread-safety is using the lock statement:
public static class People
{
static List<string> _names = new List<string>();
public static void AddName(string name)
{
lock (_names)
{
_names.Add(name);
}
}
public static IEnumerable<string> GetNames()
{
lock(_names)
{
return _names.ToArray();
}
}
}
public class Threading
{
public static async Task DoSomething()
{
var t1 = new Task1("bob");
var t2 = new Task1("erin");
await Task.WhenAll(t1,t2);
}
private static async Task Task1(string name)
{
People.AddName(name);
}
}
of course it's not very usefull (why not just add without the threads) - but I hope you get the idea.
If you don't use some kind of lock and concurrently read and write to a List you will most likely get an InvalidOperationException saying the collection has changed during read.
Because you don't really know when a user will use the collection you might return the easiest way to get thread-saftey is copying the collection into an array and returning this.
If this is not practical (collection to large, ..) you have to use the classes in System.Collections.Concurrrent for example the BlockingCollection but those are a bit more involved.

Categories

Resources