I am currently working on a simulation class library that will be used by other programmers to create a dynamic simulation timeline and run these simulations.
In a sense, this is done by letting the user of the library specify actions on certain points in simulated time.
But I am now running into problems where an action that has been created by the user can be either async or not. To keep the simulation consistent though I need to execute both variants synchronously. I boiled the problem down to a very simple example:
class Program
{
static void Main()
{
Action action = ActionFromUser();
action();
Console.WriteLine("2");
Console.ReadKey();
}
static Action ActionFromUser()
{
Random rng = new Random();
if (rng.Next(0, 2) == 0) // 50/50
{
return async () =>
{
await Task.Delay(1000);
Console.WriteLine("1");
};
}
else
{
return () =>
{
Thread.Sleep(1000);
Console.WriteLine("1");
};
}
}
}
The problem now comes down to that the output is dependent on whether the action is async or sync which is the behavior I want to get rid of.
The action will always be without parameters and without a return value.
I do not want to use reflection (action.Method.IsDefined(typeof(AsyncStateMachineAttribute), ...).
I tried switching from Action to delegate (Func does not seem to be a good option since I have to specify a return value type) but I haven't found anything there that would help me.
An async lambda on an Action, is an async void. It's highly unlikely you'd want this . If in doubt change it to a Func<Task> and return a completed task on the synchronous result, and await the results.
Note : this is a contrived example, I'd imagine your code is a lot different, however it illustrates the point:
static Func<Task> FromUserAsync()
{
Random rng = new Random();
if (rng.Next(0, 2) == 0) // 50/50
{
return async () =>
{
await Task.Delay(1000);
Console.WriteLine("1");
};
}
else
{
return () =>
{
Thread.Sleep(1000);
Console.WriteLine("1");
return Task.CompletedTask;
};
}
}
One last note, you should probably catch any exceptions in the synchronous path and place them on the task, with Task.FromException
Related
I was recently exposed to C# language and was working on getting data out of cassandra so I was working with below code which gets data from Cassandra and it works fine.
Only problem I have is in my ProcessCassQuery method - I am passing CancellationToken.None to my requestExecuter Function which might not be the right thing to do. What should be the right way to handle that case and what should I do to handle it correctly?
/**
*
* Below method does multiple async calls on each table for their corresponding id's by limiting it down using Semaphore.
*
*/
private async Task<List<T>> ProcessCassQueries<T>(IList<int> ids, Func<CancellationToken, int, Task<T>> mapperFunc, string msg) where T : class
{
var tasks = ids.Select(async id =>
{
await semaphore.WaitAsync();
try
{
ProcessCassQuery(ct => mapperFunc(ct, id), msg);
}
finally
{
semaphore.Release();
}
});
return (await Task.WhenAll(tasks)).Where(e => e != null).ToList();
}
// this might not be good idea to do it. how can I improve below method?
private Task<T> ProcessCassQuery<T>(Func<CancellationToken, Task<T>> requestExecuter, string msg) where T : class
{
return requestExecuter(CancellationToken.None);
}
As said in the official documentation, the cancellation token allows propagating a cancellation signal. This can be useful for example, to cancel long-running operations that for some reason do not make sense anymore or that are simply taking too long.
The CancelationTokenSource will allow you to get a custom token that you can pass to the requestExecutor. It will also provide the means for cancelling a running Task.
private CancellationTokenSource cts = new CancellationTokenSource();
// ...
private Task<T> ProcessCassQuery<T>(Func<CancellationToken, Task<T>> requestExecuter, string msg) where T : class
{
return requestExecuter(cts.Token);
}
Example
Let's take a look at a different minimal/dummy example so we can look at the inside of it.
Consider the following method, GetSomethingAsync that will yield return an incrementing integer every second.
The call to token.ThrowIfCancellationRequested will make sure a TaskCanceledException is thrown if this process is cancelled by an outside action. Other approaches can be taken, for example, check if token.IsCancellationRequested is true and do something about it.
private static async IAsyncEnumerable<int> GetSomethingAsync(CancellationToken token)
{
Console.WriteLine("starting to get something");
token.ThrowIfCancellationRequested();
for (var i = 0; i < 100; i++)
{
await Task.Delay(1000, token);
yield return i;
}
Console.WriteLine("finished getting something");
}
Now let's build the main method to call the above method.
public static async Task Main()
{
var cts = new CancellationTokenSource();
// cancel it after 3 seconds, just for demo purposes
cts.CancelAfter(3000);
// or: Task.Delay(3000).ContinueWith(_ => { cts.Cancel(); });
await foreach (var i in GetSomethingAsync(cts.Token))
{
Console.WriteLine(i);
}
}
If we run this, we will get an output that should look like:
starting to get something
0
1
Unhandled exception. System.Threading.Tasks.TaskCanceledException: A task was canceled.
Of course, this is just a dummy example, the cancellation could be triggered by a user action, or some event that happens, it does not have to be a timer.
I want to create some async Tasks without starting them at the moment.
With the untyped Tasks there is no problem:
private Task CreateTask() {
return new Task(
async () => await DoSomething().ConfigureAwait(false));
}
But to handle Exceptions I added a return value to my function. But how can I write it in a correct syntax:
private Task<bool> CreateTask() {
return new Task<bool>(
async () => await DoSomething().ConfigureAwait(false));
}
I get the message, that the async lambda expression can't be converted to func.
So my question: How is it written correctly?
I want to create some async Tasks without starting them at the moment.
That is the wrong solution for whatever problem you're trying to solve. If you want to define code that you want to run in the future, then you should use a delegate:
private Func<Task> CreateTaskFactory()
{
return async () => await DoSomething().ConfigureAwait(false);
}
But to handle Exceptions I added a return value to my function.
Again, that's not the best solution. Tasks already understand exceptions just fine without writing any additional code.
If you do need to return a value (as data), then you can return a delegate that creates a Task<T>:
private Func<Task<int>> CreateTaskFactory()
{
return async () => await DoSomethingReturningInt().ConfigureAwait(false);
}
I have an database I access using Entity Framework and a set of actions that I need to execute in order on remote machines. The machines communicate when they're done by updating the database and don't report back otherwise. Given the architecture of the rest of the code, providing some event that I can hook into would be difficult (although that would be ideal). An example of what I'm attempting to do is:
private enum Machines
{
SetA,
SetB
};
private void Action()
{
ExecuteWork(Machines.SetA);
while (!IsWorkDone(Machines.SetA))
{
Thread.Sleep(TimeSpan.FromMinutes(1));
}
ExecuteWork(Machines.SetB);
}
private void ExecuteWork(Machines machineGroup)
{
// Do long running work on every remote machine in this set, between 10-40 minutes.
// When this work is completed, each machine reports its completion to a database.
}
Is there a better way to hold off executing the next action until the first action has finished if the limitation is that we have to rely on the database for the status update to go ahead?
private bool IsWorkDone(Machines machineGroup)
{
using (_context = new DbContext())
{
var machines = _context.Machines.Where(machine => machine.Group.Equals(machineGroup.ToString(), StringComparison.OrdinalIgnoreCase));
foreach (var machine in machines)
{
if (machine.Status == Status.Incomplete)
{
return false;
}
}
return true;
}
}
I would suggest using async, await, and Task for this. Without to much work, you can change your Action() function to be:
private async Task Action()
{
ExecuteWork(Machines.SetA);
while (!IsWorkDone(Machines.SetA))
{
await Task.Delay(TimeSpan.FromMinutes(1));
}
ExecuteWork(Machines.SetB);
}
While this still waits for ExecuteWork() to complete, it does so in a non blocking way. So the code that would call Action() would then look like:
//does not have to be async
private async Task Test()
{
//Action will execute until it hits the await Task.Delay(),
//at which point, execution will return to this function
//(if Test() is marked async) until the time span is up.
Task t = Action();
//If Test() is not async, I believe that Action() will run
//on a separate thread, but I may be wrong.
for(int i = 0; i < 100; i++){
console.log(i);
}
//At this point, execution of Test() will stop until
//Action() finnishes, and the calling function will continue if it
//has the async modifier.
await t;
}
If the function was not marked async Task, but simply void, you would wait for t to complete by using t.Wait().
I have a class used as a parent to all my ViewModels. It contains a specific method used to call others methods, and show loading messages and message boxes on error (mainly):
public class BaseViewModel
{
async public void Try(Func<Task> action, string errorMessage = null, string waitMessage = null)
{
try
{
if (waitMessage != null)
ShowLoading(waitMessage);
await action();
}
catch (Exception e)
{
ShowError(errorMessage, e);
}
finally
{
HideLoading();
}
}
}
It is asynchronous, so my ShowLoading can be animated and stuff like that.
Is it correctly implemented?
It will always get anonymous (lambda) parameterless Tasks. My main issue is on how to actually construct these Tasks. Let's say I have a Command in a ViewModelBase's child, which call the following method when executed:
private void OnMyCommandExecute()
{
Try(() =>
{
Thread.Sleep(5000);
}, "error", "please wait");
}
It does not compile because Not all code paths return a value in lambda expression of type 'System.Func<System.Threading.Tasks.Task>'. Obvious, since we await this Func. Which leads me to the second question:
What should I put inside my Try call in this example for it to work?
I tried some really ugly things, and I really hope the answer is way different, else it will be a pain of readability:
Try(async () =>
{
return await Task.Factory.StartNew(() =>
{
SharePointService.Connect(Connection);
IsConnected = true;
});
}
It does not compile, but at this point, it's better like that. Error on return: Since 'System.Func<System.Threading.Tasks.Task>' is anasyncmethod that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?
Try accepts a method that returns a Task. In your first example you're providing a method that is void.
In your second example you're providing a method that returns a Task<Task>, but trying to use it in a context where a Task (non-generic) is expected.
If you want to use a non-async lambda, then just have that lambda return the Task that you want to use:
Try(()=>Task.Factory.StartNew(() =>
{
SharePointService.Connect(Connection);
IsConnected = true;
}));
If you want to use an async lambda, then you need to await the task without returning it:
Try(async () => await Task.Factory.StartNew(() =>
{
SharePointService.Connect(Connection);
IsConnected = true;
}));
Note that there's no real purpose to having an async lambda here. These two snippets will both perform identically, but the second adds some extra overhead in code bloat as well as a whole state machine that just isn't actually needed at runtime.
What should I put inside my Try call in this example for it to work?
You need to make that lambda expression async by adding (surprisingly) async:
Try(async () =>
{
Thread.Sleep(5000);
}, "error", "please wait");
However, while this will enable you to create an async delegate there's nothing actually asynchronous about it (it blocks the calling thread with Thread.Sleep). If this is just an example then:
Try(async () =>
{
await Task.Delay(5000);
}, "error", "please wait");
is a better one. If it isn't don't use async at all.
Is it correctly implemented?
Not really. async void should almost always be avoided (unless in a UI event handler). Use async Task instead and make sure to await the returned task in some point to ensure the operation completed without any exceptions.
In order for Try to be as transparent as possible, I ended up with this.
async public Task Try(Action action, string errorMessage = null, string waitMessage = null)
{
try
{
if (waitMessage != null)
{
ShowLoading(waitMessage);
await Task.Factory.StartNew(() => action());
}
else
action();
}
catch (Exception e)
{
ShowError(errorMessage, e);
}
finally
{
HideLoading();
}
}
Therefore, you don't have to work with Task.Factory.StartNew or async/await when you call it:
Try(() =>
{
Thread.Sleep(5000);
}, "error", "please wait");
I have an abstract class called VehicleInfoFetcher which returns information asynchronously from a WebClient via this method:
public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID);
I'd like to combine the results of two separate instances of this class, running each in parallel before combining the results. This is done within a third class, CombinedVehicleInfoFetcher (also itself a subclass of VehicleInfoFetcher)
Here's my code - but I'm not quite convinced that it's running the tasks in parallel; am I doing it right? Could it be optimized?
public class CombinedVehicleInfoFetcher : VehicleInfoFetcher
{
public HashSet<VehicleInfoFetcher> VehicleInfoFetchers { get; set; }
public override async Task<DTOrealtimeinfo> getVehicleInfo(string stopID)
{
// Create a list of parallel tasks to run
var resultTasks = new List<Task<DTOrealtimeinfo>>();
foreach (VehicleInfoFetcher fetcher in VehicleInfoFetchers)
resultTasks.Add(fetcher.getVehicleInfo(stopID, stopID2, timePointLocal));
// run each task
foreach (var task in resultTasks)
await task;
// Wait for all the results to come in
await Task.WhenAll(resultTasks.ToArray());
// combine the results
var allRealtimeResults = new List<DTOrealtimeinfo>( resultTasks.Select(t => t.Result) );
return combineTaskResults(allRealtimeResults);
}
DTOrealtimeinfo combineTaskResults(List<DTOrealtimeinfo> realtimeResults)
{
// ...
return rtInfoOutput;
}
}
Edit
Some very helpful answers, here is a re-written example to aid discussion with usr below:
public override async Task<object> combineResults()
{
// Create a list of parallel tasks to run
var resultTasks= new List<object>();
foreach (AnotherClass cls in this.OtherClasses)
resultTasks.Add(cls.getResults() );
// Point A - have the cls.getResults() methods been called yet?
// Wait for all the results to come in
await Task.WhenAll(resultTasks.ToArray());
// combine the results
return new List<object>( resultTasks.Select(t => t.Result) );
}
}
Almost all tasks start out already started. Probably, whatever fetcher.getVehicleInfo returns is already started. So you can remove:
// run each task
foreach (var task in resultTasks)
await task;
Task.WhenAll is faster and has better error behavior (you want all exceptions to be propagated, not just the first you happen to stumble upon).
Also, await does not start a task. It waits for completion. You have to arrange for the tasks to be started separately, but as I said, almost all tasks are already started when you get them. This is best-practice as well.
To help our discussion in the comments:
Task Test1() { return new Task(() => {}); }
Task Test2() { return Task.Factory.StartNew(() => {}); }
Task Test3() { return new FileStream("").ReadAsync(...); }
Task Test4() { return new TaskCompletionSource<object>().Task; }
Does not "run" when returned from the method. Must be started. Bad practice.
Runs when returned. Does not matter what you do with it, it is already running. Not necessary to add it to a list or store it somewhere.
Already runs like (2).
The notion of running does not make sense here. This task will never complete although it cannot be explicitly started.