Continue method execution without waiting for other method execution - c#

I want to call a method inside some method and do not want the process to wait or take time on other method completion.
like this
public ActionResult Insert(int userId)
{
_userService.Insert(userId);
SyncUserInSomeOtherCollection(userId);
return new EmptyResult();
}
private SyncUserInSomeOtherCollection(int userId)
{
//Do Sync work which will actually take some time
}
I want to make SyncUserInSomeOtherCollection() work in such a way so that the main method return result without any wait.
I tried to run a task like this
Task.Run(async () => await SyncUserInSomeOtherCollection(userId)).Result;
But not sure if this a good approach to follow.

Based on the code that you shared, I assume you're working on ASP.NET. I've come across same scenario and found QueueBackgroundWorkItem to work for me, it also allows you to have graceful shutdown of your long running task when Worker Process is stopped / shutdown.
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
if (!cancellationToken.IsCancellationRequested)
{
//Do Action
}
else
{
//Handle Graceful Shutdown
}
}
There are more ways to accomplish this. I suggest you go through this excellent article by Scott Hanselman.

Related

Blocking main thread with SemaphoreSlim until background event arrives

Yes, I know, there are tons of threads on this topic. I read a lot of them and used them often (more or less) successfully. Now I got an old DLL (programmed in .net 4.0) and that is using BackgroundWorkers to fire result events. Whatever I try to stop and wait for such a result seems to miss its mark. But maybe some of you have ideas that I haven't tried yet.
I register the answer event in thread 1 (according to Thread.CurrentThread.ManagedThreadId), call the method to connect and wait with a SemaphoreSlim for the answer. But in each and every constellation I get the answering event AFTER the timeout occurred. The event is on thread 3 and when I tried to raise the AwaitAsync() (also with Await) of the SemaphoreSlim on a special Thread.Run(() => ...); it was on thread id 8. But still thread number 3 always just comes AFTER the timeout.
private void ConnectDevice()
{
MobileDevice.DeviceConnected += new DeviceConnectedHandler(MobileDevice_Connected);
...
mSignal = new SemaphoreSlim(0, 1);
MobileDevice.Connect();
// Task.Run(() => MobileDevice.Connect());
int i = Thread.CurrentThread.ManagedThreadId;
var task = Task.Run(() => mSignal.WaitAsync(new TimeSpan(0, 0, cTimeout)).GetAwaiter().GetResult());
// Task<bool> task = Task.Run(async () => await WaitForSemaphore());
// var result = task.Wait();
IsConnected = task.Result;
// WaitForSemaphore();
...
}
private async Task<bool> WaitForSemaphore()
{
int j = Thread.CurrentThread.ManagedThreadId;
if (!await mSignal.WaitAsync(new TimeSpan(0, 0, 5)))
{
throw new MobileDeviceException("Device timed out");
}
return true;
}
//private void WaitForSemaphore()
//{
// if (!mSignal.Wait(new TimeSpan(0, 0, cTimeout)))
// {
// throw new MobileDeviceException("Device timed out");
// }
//}
private void MobileDevice_Connected(object sender, DeviceConnectedEventArgs e)
{
int k = Thread.CurrentThread.ManagedThreadId;
mSignal?.Release();
...
}
And yes, I know this is chaotic. But I wanted to show you, that I tried a lot already. I tried a lot more, but deleted also a mass of mistakes.
I begin to think, that, even if the answer comes on thread id 3, the listener to these events is still the main thread (id 1). And as long as that is blocked, the event doesn't gets fired.
Am I right? And how do I get around this? Register the event on a different way?
Oh, I nearly forgot: I am serving an Interface here and this will become a plugin for a complex application, so I cannot make the Connect-Method async and use the async/await-Pattern. I have to call the Connect of the device, block the main thread till the answer arrives and then release it, so the main part of the application can continue.
Anyone an idea of solving this?
Edit (the 1st): Ok, to sort some confusions out. This is a plugin that is called from a non-async method. I cannot change the calling method to an async one or else I would have to reprogram a few hundred thousand lines of code.
The call comes from the main program and looks like this:
firstDevice.Connect();
I COULD change that to something within reason, but I cannot use something like: await firstDevice.Connect(); or else I would have to change the main programs calls all to async. And this is simply out of question.
The connect method inside the plug-in I could change. At this moment it does nothing more than to call the ConnectDevice(), so I could test some things with async, SemaphoreSlims, and so on.
And as soon as I use an await inside an async method, the calling thread moves on. There would also have to be an await, but you cannot use await outside of async methods.
What seems strange to me is, that Thread.CurrentThread.ManagedThreadId says that both threads are thread 1. But when I step through they are clearly moving asynchronously.
Edit (the 2nd): I heard a clue. Maybe the problem here is the BackgroundWorker of the API. A colleague of mine once heard that the BackgroundWorker blocks the GUI-thread, when it is started on the GUI-thread. So the events of the API cannot get to me on thread 3 until the GUI-thread is released. So the solution would be to call the MobileDevice.Connect(); on a different thread. But it seems that the API will have to change. So we will discuss this internally. As soon as I have a solution I will update this a last time for anyone interested.
Edit (the 3rd): Ok, it seems nearly all of this solutions are working my problem was really with this goddamn BackgroundWorker. The API communicated with the mobile device on thread 1. And as soon as you block thread 1, there is also a block in the communication between API and device, so the answer of the API never comes...
But thanks anyway for you help. ;)
You may wrap the Connect call in a TaskCompletionSource:
public static class DeviceExtension
{
public static Task ConnectAsync(this Device device)
{
var tcs = new TaskCompletionSource<object>();
device.DeviceConnected += (s, e) => tcs.SetResult(null);
device.Connect();
return tcs.Task;
}
}
which you would call like
await MobileDevice.ConnectAsync();
or in a synchronous context like
MobileDevice.ConnectAsync().Wait();

Is it possible to wait for Device.BeginInvokeOnMainThread code to finish (continue background work with results of a UI call)

In my code I have a task called "ShowMessageBoxAsync". I want to use this code to show (and await) the DisplayAlert to the user and return the result. Like this: var messageBoxResult = await View.ShowMessageBoxAsync("This is an error");
The code for the ShowMessageBoxAsync is:
public async System.Threading.Tasks.Task<bool> ShowMessageBoxAsync(string message)
{
var result = false;
Device.BeginInvokeOnMainThread(async () =>
{
result = await DisplayAlert("Error", message, "OK", "Cancel");
});
return result;
}
Before I added the Device.BeginInvokeOnMainThread, the task gave me an Exception that it wasn't running on the main/UI thread. So after adding BeginInvokeOnMainThread, it started to work without exceptions. The problem, however, is that the code goes directly to the result, without waiting for the result of the "await DisplayAlert".
Is it possible return the value of "result" only after the Device.BeginInvokeOnMainThread code finishes?
I did some research about it and someone suggested to use a TaskCompletionSource, but this blocks the UI thread and the DisplayAlert doesn't show up at all.
I did some research about it and someone suggested to use a TaskCompletionSource
That is the correct solution. TaskCompletionSource acts as a "completer" for a Task. In this case, this Task is representing the user interaction, so you want the code on the UI thread to do the completing of the Task, and the code on the background thread to (a)wait for the `Task.
So, something like this:
public Task<bool> ShowMessageBoxAsync(string message)
{
var tcs = new TaskCompletionSource<bool>();
Device.BeginInvokeOnMainThread(async () =>
{
try
{
var result = await DisplayAlert("Error", message, "OK", "Cancel");
tcs.TrySetResult(result);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
This should get you unblocked for now. However, a better long-term solution would be to have your background thread logic take some kind of "interact with the UI" interface like this:
public interface IAskUser
{
Task<bool> AskUserAsync(string message);
}
with a Xamarin-Forms-specific implementation similar to above.
That way, your background thread logic isn't tied to a specific UI, and can be more easily unit tested and reused.
This question is worth an update now - in the latest version of Xamarin Forms there is now an awaitable method called Device.InvokeOnMainThreadAsync which is easier to use and less verbose than the other answers, in my opinion.
var result = false;
await Device.InvokeOnMainThreadAsync(async () =>
{
result = await DisplayAlert("Error", message, "OK", "Cancel");
});
return result;
Or if you're not running in Xamarin forms you can reference Xamarin.Essentials from Xamarin.iOS, Xamarin.Android or Xamarin.UWP too and call the MainThread extension like this
var result = false;
await MainThread.InvokeOnMainThreadAsync(async () =>
{
result = await DisplayAlert("Error", message, "OK", "Cancel");
})
return result;
You can do that using ManualResetEvent like:
var mre = new ManualResetEvent(false);
Device.BeginInvokeOnMainThread(() =>
{
// do whatever
mre.Set();
});
mre.WaitOne();
//continues when the UI thread completes the work
To be very honest in my Knowledge what you are trying to achieve here is not possible.
Because BeginInvokeOnMainThread is a void method that takes an action, and both of them cannot return anything.
But I am curious about something else here that being, DisplayAlert is a Task<bool> returning method then why do you want to wrap it in another Task<bool>? Can't you just directly use it wherever you need it I mean it's quite possible to do that isn't it?
Feel free to revert in case of queries
Goodluck!
If you choose to use C# async/await, you must get on to the correct thread before calling any async method. Put a breakpoint on the start of the method in your question - before it calls BeginInvoke. Go up your call stack, till you get to a method that isn't declared async. That is the method that must do BeginInvokeOnMainThread, as a wrapper around all your async code.
Be sure to remove BeginInvokeOnMainThread from the code you showed - once you are inside async/await, that won't do what you want.
DISCLAIMER: It would be better to instead make a fundamental change somewhere else.
Why are you on a background thread, but require a UI call?
There are a variety of mechanisms for splitting your code into the UI portion and the background portion: you haven't fully done so, or you wouldn't be having this problem.
Perhaps you need a background task with a progress callback. That callback communicates with user as needed.
Or you need to have the background task's "completion" report to your main code that it cannot continue without user input, do the user input in that main code, then start another background task to finish the work.
Or earlier in your code, before beginning your background task, you needed to verify that you had all needed info from user, and communicate there.
If those aren't enough hints to head you in a workable direction, I recommend finding a more complete example of async/await used in an app, study what it does. If you still have this question, then add more detail to it.
That's the "pure" answer.
In practice, I have found it sometimes easier to throw in a BeginInvokeOnMainThread - and then write code without async/await.
G.Hakim made the essential observation:
DisplayAlert is a Task returning method ...
See Microsoft doc- Chaining Tasks by Using Continuation Tasks if you want to understand how to call DisplayAlert, then do something else afterwards.
Going down this road, I think you need to remove async and await from your method. You'll be doing the "asynchronous" calling yourself.
Instead of trying to do work after that method returns, you'll pass in a parameter with the work to be done next. Something like:
public void ShowMessageBoxAsync(string message, Action afterAction)
{
Device.BeginInvokeOnMainThread(() =>
{
// See "Chaining Tasks ..." link. Use "afterAction" as "continuation".
... DisplayAlert("Error", message, "OK", "Cancel") ...
});
}
"afterAction" is what will become the "continuation".
Sorry, I don't have the details at my fingertips - see above link.

C# MVC Async Task<> Controller Action Confusion [duplicate]

I have a process I would like to run in the background. This is executed with a click of an action link.
Action to call:
public async Task<ActionResult> ProcessRec()
{
await Task.Run(() => waitTimer());
return RedirectToAction("Index", "Home");
}
public void waitTimer()
{
Thread.Sleep(10000);
}
This however waits for the full 10 seconds before redirecting me to my "Index, Home" action. I am very new to Await/Async so I know I am interpreting something wrong here. How do I get the application to return to this action, while the waitTimer is executing in the background? Thanks!!
await, as you found out, blocks the response from returning to the user before it is done. Normally you would just put your background work on another thread and set it to "fire and forget" by not awaiting, however in ASP.NET IIS will shut down AppDomains that are not being used and Task.Run does not inform IIS that your background thread "is using the AppDomain" so your background thread could be terminated with a Thread.Abort() during an AppDomain shutdown.
If you are using .NET 4.5.2 or newer you can tell IIS you have a background worker that you need to be kept alive via QueueBackgroundWorkItem. You would use it like this
public ActionResult ProcessRec()
{
HostingEnvironment.QueueBackgroundWorkItem(waitTimer);
return RedirectToAction("Index", "Home");
}
public void waitTimer(CancellationToken token)
{
Thread.Sleep(10000);
}
//You also could do
public async Task waitTimer2(CancellationToken token)
{
await Task.Delay(10000);
}
Now this does not guarantee that IIS will not shut down your app domain but it does let it know you are in the middle of something and asks for more time when it does try to shut it down (You get up to 90 additional seconds after a shutdown is started to complete all queued background items by default).
For more information read this MSDN blog introducing it.
This however waits for the full 10 seconds before redirecting me to my "Index, Home" action.
Right, that's because await asynchronously waits for the operations completion. It will yield the thread back to the pool until the operation completes.
How do I get the application to return to this action, while the waitTimer is executing in the background?
Task.Run is dangerous in the fact it doesn't register work with IIS which can lead to problems. Instead, you can use BackgroundTaskManager or HangFire which register it's execution with ASP.NET:
BackgroundTaskManager.Run(() => { waitTimer() };
return RedirectToAction("Index", "Home");
I'm thinking about sending a message to a queue (like azure storage/service bus queue) so that you can get your response immediately.
And then create another service to dequeue and process the message (execute your long running task)
Also if this is an azure website (web app), you can use the web job!
Hope that helps.
public async Task<IActionResult> Index()
{
return await Task.Run(() =>
{
return View();
});
}

ASP.NET MVC Async Action doesn't work properly

I have an issue with this simple async code. The execution goes througth the TestAsync action and goes througth the delay method but when the delay method returns nothing else happens.
it seems like blocked for some reason.
public async Task<ActionResult> TestAsync()
{
try
{
var res = await doLongOperation();
return RedirectToAction("Index");
}
catch (Exception e) { }
}
private Task<bool> doLongOperation()
{
var test = new Task<bool>(() => { /*do the long operation..*/ return true; });
return test;
}
Any suggestion?
new Task<bool>(() => true) returns a task that is not started yet. This is an old syntax that requires you to invoke the Start method on the task. If you don't invoke the Start method, the task will never complete, and thus asynchronous execution will never continue (await will asynchronously wait forever).
If you simply want to delay execution, then simply use Task.Delay like this:
private async Task<bool> delay()
{
await Task.Delay(1000);
return true;
}
In general, it is always recommended to create tasks that are already started upon creation.
If you want to create a task that runs on a thread-pool thread, then use the Task.Run method.
The method posted in your question doesn't work properly because the task is not started, there's nothing finishing so your await is waiting indefinitely. If you want to use Async it's best to use async all the way down, especially in an ASP.NET context. If you are not doing anything that is truly asynchronous, then in a web development context, just allow it to be synchronous.
I honestly believe the most good that will be done here is for you to spend time studying async/await, an excellent resource is found here: Stephen Cleary Blog on Async

What's the correct way to run multiple parallel tasks in an asp.net process?

I think I'm not understanding something. I had thought that Task.Yield() forced a new thread/context to be started for a task but upon re-reading this answer it seems that it merely forces the method to be async. It will still be on the same context.
What's the correct way - in an asp.net process - to create and run multiple tasks in parallel without causing deadlock?
In other words, suppose I have the following method:
async Task createFileFromLongRunningComputation(int input) {
//many levels of async code
}
And when a certain POST route is hit, I want to simultaneously launch the above methods 3 times, return immediately, but log when all three are done.
I think I need to put something like this into my action
public IHttpAction Post() {
Task.WhenAll(
createFileFromLongRunningComputation(1),
createFileFromLongRunningComputation(2),
createFileFromLongRunningComputation(3)
).ContinueWith((Task t) =>
logger.Log("Computation completed")
).ConfigureAwait(false);
return Ok();
}
What needs to go into createFileFromLongRunningComputation? I had thought Task.Yield was correct but it apparently is not.
The correct way to offload concurrent work to different threads is to use Task.Run as rossipedia suggested.
The best solutions for background processing in ASP.Net (where your AppDomain can be recycled/shut down automatically together with all your tasks) are in Scott Hanselman and Stephen Cleary's blogs (e.g. HangFire)
However, you could utilize Task.Yield together with ConfigureAwait(false) to achieve the same.
All Task.Yield does is return an awaiter that makes sure the rest of the method doesn't proceed synchronously (by having IsCompleted return false and OnCompleted execute the Action parameter immediately). ConfigureAwait(false) disregards the SynchronizationContext and so forces the rest of the method to execute on a ThreadPool thread.
If you use both together you can make sure an async method returns a task immediately which will execute on a ThreadPool thread (like Task.Run):
async Task CreateFileFromLongRunningComputation(int input)
{
await Task.Yield().ConfigureAwait(false);
// executed on a ThreadPool thread
}
Edit:
George Mauer pointed out that since Task.Yield returns YieldAwaitable you can't use ConfigureAwait(false) which is a method on the Task class.
You can achieve something similar by using Task.Delay with a very short timeout, so it wouldn't be synchronous but you wouldn't waste much time:
async Task CreateFileFromLongRunningComputation(int input)
{
await Task.Delay(1).ConfigureAwait(false);
// executed on a ThreadPool thread
}
A better option would be to create a YieldAwaitable that simply disregards the SynchronizationContext the same as using ConfigureAwait(false) does:
async Task CreateFileFromLongRunningComputation(int input)
{
await new NoContextYieldAwaitable();
// executed on a ThreadPool thread
}
public struct NoContextYieldAwaitable
{
public NoContextYieldAwaiter GetAwaiter() { return new NoContextYieldAwaiter(); }
public struct NoContextYieldAwaiter : INotifyCompletion
{
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation)
{
var scheduler = TaskScheduler.Current;
if (scheduler == TaskScheduler.Default)
{
ThreadPool.QueueUserWorkItem(RunAction, continuation);
}
else
{
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.PreferFairness, scheduler);
}
}
public void GetResult() { }
private static void RunAction(object state) { ((Action)state)(); }
}
}
This isn't a recommendation, it's an answer to your Task.Yield questions.
(l3arnon's answer is the correct one. This answer is more of a discussion on whether the approach posed by the OP is a good one.)
You don't need anything special, really. The createFileFromLongRunningComputation method doesn't need anything special, just make sure you are awaiting some async method in it and the ConfigureAwait(false) should avoid the deadlock, assuming you're not doing anything out of the ordinary (probably just file I/O, given the method name).
Caveat:
This is risky. ASP.net will most likely pull the rug out from under you in this situation if the tasks take too long to finish.
As one of the commenters pointed out, there are better ways of accomplishing this. One of them is HostingEnvironment.QueueBackgroundWorkItem (which is only available in .NET 4.5.2 and up).
If the long running computation takes a significantly long time to complete, you're probably better off keeping it out of ASP.net entirely. In that situation, a better method would be to use some sort of message queue, and a service that processes those messages outside of IIS/ASP.net.

Categories

Resources