0

I'm trying to call an asynchronous method from a synchronous method like below:

1.  public List<Words> Get(string code)
    {           
        Task<List<Words>> taskWords = GetWordsAsync(code);
        var result = taskWords.Result;
        return result;

    }
    private  async Task<List<Words>> GetWordsAsync(string code)
    {
        var result = await codeService.GetWordsByCodeAsync(code);
        return result;
    }

But this lead to a deadlock, await is not getting the results from the method - GetWordsByCodeAsync I've done a bit of research and came to know that if we are calling an async method from synchronous method we should use Task.Run

When I changed the code like below, it worked:

2.  public List<Words> Get(string code)
    {           
       Task<List<Words>> taskWords = Task.Run<List<Words>>(async () => await GetWordsAsync(code);
        var result = taskWords.Result;
        return result;

    }
    private  async Task<List<Words>> GetWordsAsync(string code)
    {
        var result = await codeService.GetWordsByCodeAsync(code);
        return result;
    }

But I didn't get the context, why it caused a deadlock for 1st way and 2nd one worked fine.

I'd like to know: What's the difference between two ways? Is second one the correct way to call async method from synchronous method? Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?

Also, please suggest any best practices to better do it as I have to do 5 async calls from a synchronous method - just like taskWords, I have taskSentences etc.,

Note: I don't want to change everything to async. I want to call async method from synchronous method.

1 Answer 1

1

I don't want to change everything to async. I want to call async method from synchronous method.

From a technical standpoint, this doesn't make sense. Asynchronous means it doesn't block the calling thread; synchronous means it does. So you understand that if you block on asynchronous code, then it's no longer truly asynchronous? The only benefit to asynchronous code is that it doesn't block the calling thread, so if you block on the asynchronous code, you're removing all the benefit of asynchrony in the first place.

The only good answer is to go async all the way. There are some rare scenarios where that's not possible, though.

What's the difference between two ways?

The first one executes the asynchronous code directly and then blocks the calling thread, waiting for it to finish. You're running into a deadlock because the asynchronous code is attempting to resume on the calling context (which await does by default), and presumably you're running this code on a UI thread or in an ASP.NET Classic request context, which only allow one thread in the context at a time. There's already a thread in the context (the one blocking, waiting for the task to finish), so the async method cannot resume and actually finish.

The second one executes the asynchronous code on a thread pool thread and then blocks the calling thread, waiting for it to finish. There is no deadlock here because the asynchronous code resumes on its calling context, which is a thread pool context, so it just continues executing on any available thread pool thread.

Is second one the correct way to call async method from synchronous method?

There is no "correct" way to do this. There are a variety of hacks, each of which has different drawbacks, and none of which work in every situation.

Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?

It will not deadlock. What it does, though, is execute GetWordsAsync on a thread pool thread. As long as GetWordsAsync can be run on a thread pool thread, then it will work.

Also, please suggest any best practices to better do it

I have written an article on the subject. In your case, if GetWordsAsync is safe to call on a thread pool thread, then the "blocking thread pool hack" is acceptable.

Note that this is not the best solution; the best solution is to go async all the way. But the blocking thread pool hack is an acceptable hack if you must call asynchronous code from synchronous code (again, it's "acceptable" only if GetWordsAsync is safe to call on a thread pool thread).

I would recommend using GetAwaiter().GetResult() rather than Result, in order to avoid the AggregateException wrapper on error. Also, the explicit type arguments are unnecessary, and you can elide async/await in this case:

var taskWords = Task.Run(() => GetWordsAsync(code));
return taskWords.GetAwaiter().GetResult();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.