Reputation: 1037
I'm pretty new to threading in C#. I've got a Searchfield which triggers HTTP-Request against an API on every Key pressed. After the Request the Searchresult is displayed in a ListView in my SearchTab. Of course this freezes the UI for a few milliseconds until the HTTP-Request is finished. So I tried to make the Request Async.
private async void textBoxSearch_KeyUp(object sender, KeyEventArgs e)
{
SearchTab searchTab;
Task<SearchContainer<SearchMovie>> searchTask = searchMovie(textBoxSearch.Text);
if (searchTabExists())
{
searchTab = getSearchTab();
}
else
{
searchTab = new SearchTab();
mainTabControl.Items.Insert(mainTabControl.Items.Count, searchTab);
}
searchTab.IsSelected = true;
SearchContainer<SearchMovie> results = await searchTask;
searchTab.updateSearch(results);
}
async Task<SearchContainer<SearchMovie>> searchMovie(String query)
{
var today = await Task.FromResult<SearchContainer<SearchMovie>>(tmdbClient.SearchMovie(query, "de"));
return today;
}
This Code makes it a bit better but it still freezes the UI a bit, because at some point it has to wait for the API-Call. I want to be able to type my search smoothly without interruption and display the result if the API-Call is finished in time before another search is made (KeyPressed).
How do you solve such a problem in C#? In JAVA I would use a AsyncWorker which calls the Displaymethod after the search is finished (or cancel the worker if another search is made) so that searching and displaying isn't done in the Main-Thread.
Is there a similar construct in C#? I can only find async await solutions if I search for multithreading. Or can is use it in a way that it works like I wish.
Upvotes: 1
Views: 604
Reputation: 994
Task.FromResult
creates an already-successful task given a result. In your example, the result comes from the call to tmdbClient.SearchMovie()
. I assume this call is blocking.
This code is not truly asynchronous because you are still waiting on a blocking call. You need an asynchronous version of the tmdbClient.SearchMovie()
method. Often, these are obvious because they are suffixed with Async
. So, you need a method like tmdbClient.SearchMovieAsync()
.
If no such method is provided by your client library, then you will need to convert a blocking call to an asynchronous call.
One simple, but flawed and problematic, way of doing this is to use Task.Run
:
(This is untested pseudocode)
Task<SearchContainer<SearchMovie>> searchMovie(String query)
{
return Task.Run(() => tmdbClient.SearchMovie(query, "de"));
}
The problem here is that you are using a thread to do a network IO call, which is a bad use of resources: the background thread is waiting on the result of the blocking call and cannot be used for anything until the blocking call completes. It should give you a more responsive UI, but with the same thread resource cost as threading yet the complexity of async.
Upvotes: 6