How Would I Run an Async Task≪T≫ Method Synchronously

How would I run an async TaskT method synchronously?

Here's a workaround I found that works for all cases (including suspended dispatchers). It's not my code and I'm still working to fully understand it, but it does work.

It can be called using:

customerList = AsyncHelpers.RunSync<List<Customer>>(() => GetCustomers());

Code is from here

public static class AsyncHelpers
{
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();

SynchronizationContext.SetSynchronizationContext(oldContext);
}

/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default(T);
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}

private class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
new Queue<Tuple<SendOrPostCallback, object>>();

public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}

public override void Post(SendOrPostCallback d, object state)
{
lock (items)
{
items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
}

public void EndMessageLoop()
{
Post(_ => done = true, null);
}

public void BeginMessageLoop()
{
while (!done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
{
if (items.Count > 0)
{
task = items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
}
}
}

public override SynchronizationContext CreateCopy()
{
return this;
}
}
}

Async method call running synchronously even with await operator

Section a is synchronous code-- there is nothing about it that returns a task while it continues to run. If you want it to be async, you can break it into a different, async method. Then wait for both to complete using Task.WhenAll.

Also, you have to using Task.Delay() instead of Thread.Sleep(). Task.Delay returns a task which you can await; Thread.Sleep just blocks the thread synchronously.

async Task RunSectionA()
{
Console.WriteLine("I'm here A");
for (int i = 0; i < 30; i++)
{
Console.WriteLine($"inside for {i}");
await Task.Delay(1000);
}
}

public async Task<string> DoAsync()
{
var taskA = RunSectionA();
var taskB = ReturnsString();

await Task.WhenAll(taskA, taskB);
return await taskB;
}

I would like to run an async method synchronously when the async function causes a dialog to show on the UI?

Solved this using info form the answers provided as well as help from this question

Here's how I did it.

private async void OnEntryLosesFocus(object sender, EventArgs e) {
var vm = (MainPageViewModel)BindingContext;
if (vm == null)
{
return;
}
// A public variable in my view model which is initially set to null.
vm.UnfocusTaskCompletionSource = new TaskCompletionSource<bool>();
var saveSuccessful = await vm.CheckAndSaveData();
vm.UnfocusTaskCompletionSource.SetResult(saveSuccessful);

if (saveSuccessful && Device.RuntimePlatform == Device.UWP &&
_completedTriggeredForEntryOnUWP)
{
var navAction = vm.GetNavigationCommand();
navAction?.Invoke();
_completedTriggeredForEntryOnUWP = false;
}
/*Set this back to null. (This is very important for my use case.). Just in case this function executes completely before the Button click command executes for whatever reason */
vm.UnfocusTaskCompletionSource = null;
}

In the function for my Command attached to the button I have something like below

private async void OnButtonTap(ArrorDirection direction)
{
bool preventMove = false;

if (UnfocusTaskCompletionSource != null)
{
/*Wait for `CheckAndSaveData() from `OnEntryLoosesFocus()` to complete and get the return value. */
await UnfocusTaskCompletionSource.Task;
var dataCheckAndSaveSuccessful = UnfocusTaskCompletionSource.Task.Result;
preventMove = !dataCheckAndSaveSuccessful;
}

// Do stuff in function:
if (preventMove){
DoMove()
}


UnfocusTaskCompletionSource = null;

}

How to call asynchronous method from synchronous method in C#?

Asynchronous programming does "grow" through the code base. It has been compared to a zombie virus. The best solution is to allow it to grow, but sometimes that's not possible.

I have written a few types in my Nito.AsyncEx library for dealing with a partially-asynchronous code base. There's no solution that works in every situation, though.

Solution A

If you have a simple asynchronous method that doesn't need to synchronize back to its context, then you can use Task.WaitAndUnwrapException:

var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();

You do not want to use Task.Wait or Task.Result because they wrap exceptions in AggregateException.

This solution is only appropriate if MyAsyncMethod does not synchronize back to its context. In other words, every await in MyAsyncMethod should end with ConfigureAwait(false). This means it can't update any UI elements or access the ASP.NET request context.

Solution B

If MyAsyncMethod does need to synchronize back to its context, then you may be able to use AsyncContext.RunTask to provide a nested context:

var result = AsyncContext.RunTask(MyAsyncMethod).Result;

*Update 4/14/2014: In more recent versions of the library the API is as follows:

var result = AsyncContext.Run(MyAsyncMethod);

(It's OK to use Task.Result in this example because RunTask will propagate Task exceptions).

The reason you may need AsyncContext.RunTask instead of Task.WaitAndUnwrapException is because of a rather subtle deadlock possibility that happens on WinForms/WPF/SL/ASP.NET:

  1. A synchronous method calls an async method, obtaining a Task.
  2. The synchronous method does a blocking wait on the Task.
  3. The async method uses await without ConfigureAwait.
  4. The Task cannot complete in this situation because it only completes when the async method is finished; the async method cannot complete because it is attempting to schedule its continuation to the SynchronizationContext, and WinForms/WPF/SL/ASP.NET will not allow the continuation to run because the synchronous method is already running in that context.

This is one reason why it's a good idea to use ConfigureAwait(false) within every async method as much as possible.

Solution C

AsyncContext.RunTask won't work in every scenario. For example, if the async method awaits something that requires a UI event to complete, then you'll deadlock even with the nested context. In that case, you could start the async method on the thread pool:

var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();

However, this solution requires a MyAsyncMethod that will work in the thread pool context. So it can't update UI elements or access the ASP.NET request context. And in that case, you may as well add ConfigureAwait(false) to its await statements, and use solution A.

Update, 2019-05-01: The current "least-worst practices" are in an MSDN article here.

What is the best practice to call Async method from Sync method?

what the best practice would be?

There is no best practice, and here's why:

Every hack works in some situations and does not work in other situations. There is no hack that works in all situations. If there was a hack that worked everywhere, then that would be what everyone would use and that hack would be the best practice. But there isn't a hack that works everywhere, so there is no "best practice". There is no general-purpose solution.

The various hacks are described in this article, along with a description of the situations where each one works and doesn't.

Async method runs synchronously

The problem is that your async method is not actually doing any async work, and because of this it won't be executed asynchronously. A similar question was answered here.

If you want to force the execution to another task, you can invoke it like this:

_rowCount = await Task.Run(async () => await CheckInLogs());

This is a quick solution, but it may also solve other problems (more on this at the end).



Some other options would be to:

  • make the method synchronous (returning int instead of Task<int>) and running it explicitly in a different task with Task.Run(() => CheckInLogs())

  • actually do some async work inside the method, i.e. using the ReadLineAsync method instead of ReadLine (docs)



On using ReadLineAsync: even if using ReadLineAsync and awaiting it would execute the method in a different task (i.e. making it truly asynchronous), you may find that the calling thread is still initially blocked.

This can happen when before the first await you execute some code that takes some time to complete, and since the await has not been reached yet, the code before it runs synchronously.
In your code, the line var dataTable = ToDataTable(_manualReadTagList); could be slow enough to cause this behaviour, but this depends on the actual implementation of this function.

In this case, it would make sense to invoke the method as

await Task.Run(async () => await CheckInLogs());

even if the method is actually doing some async work at some point, because it would force to run the method in a different task immediately.

Is there a way to synchronously run a C# task and get the result in one line of code?

Yes you can do it using the Result property directly after the calling of method:

var result = someClass.myAsyncMethod(someParameter).Result;

and a more better way is to wrap it in Task.Run() to avoid deadlocks like:

var result = Task.Run(() => {

return someClass.myAsyncMethod(someParameter);

}).Result;

I also found this RunSynchronously() method on MSDN, but that won't server your question as you want a on liner simple code.

Does running a synchronous method using Task.Run() make it asynchronous

Here the method I've written to create a dictionary out of my List, does it run asynchronously?

It's probably more accurate to say it runs in parallel. A separate thread is created to produce the result. If people isn't being used in a thread-safe way (e.g. it's a List that you're adding to in other threads), then you could end up with messy race conditions.

When people talk about "Asynchronous" code, there are two things they could mean.

  1. Code that models an inherently asynchronous operation, like Disk or Network I/O, in a way that doesn't block a thread.
  2. More broadly, any kind of operation that can complete independently from the current thread of operations.

What you've done matches the second definition, but not the first. If people were backed by a database round-trip, your code would still block a thread while that call completed: it would just be blocking a different thread than the one that calls MapDepartments.

What's the difference between this and putting my dictionary logic in an asynchronous method?

Since you're pulling from an in-memory List, and all your operations are CPU-bound (not doing truly asynchronous operations), there would be no benefit to putting your logic in an async method, because there would be nothing for that method to await. Even though the method would say it's async, it would run synchronously to completion before returning a Task.

Assuming creating that dictionary really takes enough time to make it worth multi-threading, and assuming you're not modifying the underlying list before you await the Task, your current approach is better.

Whatever I've implemented is this somewhat similar to having a .ToDictionaryAsync() method?

I mean, I guess you could write a ToDictionaryAsync method that just performs ToDictionary on a separate thread, but that's really not following the spirit of what Async means.

When a library like Entity Framework provides a ToDictionaryAsync() method, that's because they know there's going to be an actual database call that will actually be asynchronous, and they know how to make that happen in a non-blocking way without calling ToDictionary(). I would reserve ToDictionaryAsync for situations like that.



Related Topics



Leave a reply



Submit