Async function not launching asynchronously - c#

I still meet issues calling async functions.
In that code, I execute generateAllIfcs(dataFolder), then I would like to execute already addToExistingContract() or this.importNewContract() depending on contexte.SourceContract.
But this line is not reached until generateAllIfcs(dataFolder) is finished.
private async void Import(object sender, RoutedEventArgs e)
{
Task<bool> successGenerateIfc = this.generateAllIfcs(dataFolder);
Task<bool> successAddContractToVsteel = contexte.SourceContract != null ?
this.addToExistingContract() : this.importNewContract();
await Task.WhenAll(successGenerateIfc, successAddContractToVsteel);
}
private async Task<bool> generateAllIfcs(string dataFolder)
{
try
{
var progressIndicator4 = new Progress<int>(contexte.ReportProgress4);
if (contexte.SourceContract != null)
{
int total4 = await contexte.NewModel.ExportNewIfcContract(
contexte.SourceContract, progressIndicator4, 0, 100,
contexte.SelectedConfigImportIFC, true,dataFolder);
}
else
{
int total4 = await contexte.NewModel.ExportNewIfcContract(null,
progressIndicator4, 0, 100, contexte.SelectedConfigImportIFC,
true, dataFolder);
}
return true;
}
catch
{
return false;
}
}
public async Task<int> ExportNewIfcContract(Contract existingContract,
IProgress<int> progress, int startProgress, int endProgress,
ConfigImportIFC config, bool generateIfcAssAndRep, string dataFolder)
{
int retour = await this.exportNewIfcContract(existingContract, progress,
startProgress, endProgress,config, generateIfcAssAndRep, dataFolder);
return retour;
}
private async Task<int> exportNewIfcContract(Contract existingContract,
IProgress<int> progress, int startProgress, int endProgress,
ConfigImportIFC config, bool generateIfcAssAndRep, string dataFolder)
{
//some other calls to async functions
}

"async function not launching asynchronously" - yes, that's normal; async isn't about how things launch, it is about how they complete (or at least, continue); async doesn't mean "parallel", "concurrent", etc - and has only tangential relationship to threading; an async method runs synchronously until the first incomplete await, i.e. where the thing being awaited did not itself finish synchronously. Only for an incomplete await does the async engine unroll itself and register a continuation. I don't see anything inherently truly async in your code, although to be fair: I can't see exportNewIfcContract.
If you want concurrency, consider Task.Run etc to invoke a second execution flow. Or alternatively, consider adding:
await Task.Yield();
at the top of generateAllIfcs (the method that you intend to run concurrently); Task.Yield() always returns in an incomplete state, pushing the rest of the work as a continuation onto the thread-pool.

Related

C# - Wait for Task with return value

I want to have a code block, which should be executed with a maximum time limit. If the functions hangs, it should be aborted.
From this question I adapted the following solution:
public static void ExecuteWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
{
Task task = Task.Factory.StartNew(() =>
{
codeBlock();
});
task.Wait(timeLimit_milliseconds);
}
This works as I want it to behave: If the code codeBlock hangs and takes to long, the task is aborted.
However, I want the Task to have a return value so I can use task.Result. If I implement this into the code, it doesn't work any more.
In fact, the task is not cancled and the GUI freezes completly.
public static void ExecuteWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
{
Task<bool> task = Task<bool>.Factory.StartNew(() =>
{
return codeBlock();
});
task.Wait(timeLimit_milliseconds);
}
What is the correct way to execute Methods with a return value with a maximum time limit?
I would recommend creating a task method and using await. This will release the thread so application doesn't lock up, and once result is available it will jump back into that thread Here is an example:
public async Task MyMethodAsync()
{
Task<string> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync can be done here
//and now we call await on the task
string result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<string> LongRunningOperationAsync() // assume we return an int from this long running operation
{
//Perform your task in here
await Task.Delay(5000); // 5 second delay to show how it releases thread
return "Task Complete";
}
There's a lot of mucking around with cancellation tokens with tasks. I'd suggest making your life easier and use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; - then you can do this:
public static async Task<bool> ExecuteWithTimeLimit(TimeSpan timeLimit, Func<bool> codeBlock)
=> await Observable.Amb(
Observable.Timer(timeLimit).Select(_ => false),
Observable.Start(() => codeBlock()));
Observable.Amb takes 2 or more observables and only returns values from whichever observable fires first. Observable.Timer fires a single value after the TimeSpan provided. Observable.Start executes what ever code and returns a single value that is the result of that code.
Effectively Amb is a race between the timer and the code.
Now I can run it like this:
Task<bool> task =
ExecuteWithTimeLimit(TimeSpan.FromSeconds(1.0), () =>
{
Console.WriteLine("!");
Thread.Sleep(TimeSpan.FromSeconds(2.0));
Console.WriteLine("!!");
return true;
});
task.Wait();
Console.WriteLine(task.Result);
When I run that I get this on the console:
!
False
!!
If I change the timeLimit to TimeSpan.FromSeconds(3.0) then I get this:
!
!!
True
Actually I found a solution by canceling the task after the time limit:
public static void ExecuteWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
{
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
Task<bool> task = Task<bool>.Factory.StartNew(() =>
{
try
{
return codeBlock();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Exeption", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}, cancellationToken);
task.Wait(timeLimit_milliseconds);
cancellationTokenSource.Cancel();
}

Understanding Task based asynchronous pattern C#

I am starting to study C# TAP coding. I don't understand why the code is running synchronously
async private void timer1_Tick(object sender, EventArgs e)
{
SyncCount++;
result1.Text = SyncCount.ToString();
AsyncCount = await CountForALongTimeAsync(AsyncCount);
result2.Text = AsyncCount.ToString();
}
async Task<int> CountForALongTimeAsync(int counter)
{
Thread.Sleep(3000);
counter++;
return counter;
}
async Task<int> CountForALongTimeAsync(int counter)
{
What comes next will be executed until the first awaited async call that actually does some waiting (it's possible that a given call could have all it needs to return immediately, e.g. a service that might hit the internet or might return data from a cache, in which case it won't wait).
There are no awaited calls at all, so the Task returned is returned already completed.
Since the calling await CountForALongTimeAsync is awaiting a task that is returned already completed, it runs synchronously.
The method would be better as:
async Task<int> CountForALongTimeAsync(int counter)
{
await Task.Delay(3000);
counter++;
return counter;
}
Incidentally, the pre await way of doing something very (but not entirely) similar would have been:
Task<int> CountForALongTimeAsync(int counter)
{
return Task.Delay(3000).ContinueWith(t =>
{
++counter;
return counter;
});
}
Considering that these are different ideas of "continuing" after a task might or might not give some insight.
In contrast the closest pre-await way of doing what the code in your question does was:
Task<int> CountForALongTimeAsync(int counter)
{
Thread.Sleep(3000);
counter++;
return Task.FromResult(counter); //FromResult returns an already completed task.
}

how to cancel a function after a while?

I want to know how can I cancel a function after a certain time!
for example, how can I cancel this function?
private async Task function()
{
try
{
while (true)
{
//mycode
}
}
catch{ }
}
how can I cancel this function?
Normally, awaitable methods will take a CancellationToken, so you'd just pass it on through:
private async Task functionAsync(CancellationToken cancellationToken)
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); //mycode
}
}
Some time ago i faced the same issue and found a pretty good solution working for me. I am separating async calls to another service via wcf this way (see my code below) by doing two things to cancel after a maximum time:
You can use CancellationToken in combination with a second Task to run parallel to your running task and cancel it if necessary:
private const int TimeOut = 50000;
public static async Task<T> HandleServiceCall<T>(Func<Task<T>> doServiceCall, CancellationTokenSource source) where T : class
{
var delaySource = new CancellationTokenSource(TimeSpan.FromSeconds(50));
source.Token.ThrowIfCancellationRequested();
var res = doServiceCall();
if (await Task.WhenAny(res, Task.Delay(TimeSpan.FromMilliseconds(TimeOut), delaySource.Token)) == res)
{
delaySource.Cancel();
await res;
}
else
{
source.Cancel();
throw new Exception("Your Text");
}
return await res;
}
You can call this Method for example this way:
var source = new CancellationTokenSource(TimeSpan.FromSeconds(50));
source.Token.ThrowIfCancellationRequested();
MyWrapperClass.HandleServiceCall(async () => await MyAsyncMethod(source.Token), source).Result
To clarify what is done here:
I am creating a cancellation Token for my Task with a given max TimeSpan and then give this Token to the async Method which should be called.
This call is given as a func into my HandleServiceCall Method.
This Method will create another CancellationToken with a given greater TimeSpan, which will Run as a delayed Task (task.Delay will just wait until the Token is triggered).
Task.WhenAny will look if the normal async task or the delayed task is finishing first. If it is the delayed one, your maximum time has expired and an exception is thrown.
Greetings
Konstantin
You could use the Timer class, start it when you want it to (beginning of the program presumably), and use some like a simple if statement to stop it, such as *if timer is greater than set time, end program. *
I add small example
static CancellationTokenSource cts;
static void Main(string[] args)
{
cts = new CancellationTokenSource();
Task.Factory.StartNew(test);
cts.Cancel();
}
private async static void test()
{
await function(cts.Token);
}
static async Task function(CancellationToken ct)
{
try
{
while (!ct.IsCancellationRequested)
{
Thread.Sleep(1000);
//mycode
}
}
catch { }
}

Wait till task returns

How do i wait my method for a task to complete before the method returns.
public async void barcodescanner()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
barcode = await scanner.Scan();
}
Definition of scaner.Scan():
public Task<Result> Scan();
You can't wait for result of async void method - it is explicitly "fire and forget" behavior.
If you want to wait for completion - return Task and .Wait on it
public async Task barcodescanner() {...}
barcodescanner().Wait();
Notes:
synchronously waiting for async methods can cause deadlocks and in general not recommended - so do it on your own risk. See await vs Task.Wait - Deadlock? for details
Difference between void and Task return covered in What's the difference between returning void and returning a Task? answer.
You could always do this:
public void barcodescanner()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
barcode = scanner.Scan().Result;
}

Monitoring Task completion

I run several tasks and keep them in a list to check if they are already completed.
I discovered that tasks that come from an async method are always shown as RanToCompletion although the task itself was still running.
Is there a way to get the "is complete" information from a Task object in both cases?
Here's a simple test case that shows this behaviour. I run two tasks, with/without an async method and check the states during and after completion.
private void test()
{
;
Action actionAsync = funcAsync;
Task taskAsync = Task.Run(actionAsync);
Action action = func;
Task task = Task.Run(action);
var statusAsync = taskAsync.Status;
var status = task.Status;
// stati are either WaitingToRun or Running
Thread.Sleep(TimeSpan.FromSeconds(2));
// Now it's quite certain, that both have started
var statusAsync2 = taskAsync.Status;
var status2 = task.Status;
Debug.Assert(statusAsync2 == TaskStatus.RanToCompletion);
Debug.Assert(status2 == TaskStatus.Running);
;
Thread.Sleep(TimeSpan.FromSeconds(12));
// Now it's quite certain, that both have finished
var statusAsync3 = taskAsync.Status;
var status3 = task.Status;
;
Debug.Assert(statusAsync3 == TaskStatus.RanToCompletion);
Debug.Assert(status3 == TaskStatus.RanToCompletion);
}
private async void funcAsync()
{
await Task.Delay(TimeSpan.FromSeconds(10));
}
private void func()
{
Thread.Sleep(TimeSpan.FromSeconds(10));
}
I discovered that tasks that come from an async method are always shown as RanToCompletion although the task itself was still running.
Yes, because your void method has completed, and that's all that Task.Run is calling. If instead you use:
private async Task FuncAsync()
{
await Task.Delay(TimeSpan.FromSeconds(10));
}
and use Func<Task> instead Action, then you'll call Task.Run(Func<Task>) and all will be well.
Short but complete example:
using System;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main()
{
Func<Task> func = FuncAsync;
Task task = Task.Run(func);
for (int i = 0; i < 7; i++)
{
Console.WriteLine(task.Status);
Thread.Sleep(1000);
}
}
private static async Task FuncAsync()
{
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
Output:
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
RanToCompletion
RanToCompletion
Try to avoid writing void async methods if you possibly can. They should basically only be used for event handlers.

Categories

Resources