2017-03-05 4 views
1

Ich habe diese Klasse:Warum blockiert mein Programm nach einer Rückkehr?

public class ImgurAPI 
{ 
    private string ClientId = "id"; 
    private string ClientSecret = "secret"; 
    private string BasicUri = "https://api.imgur.com/3/"; 
    private HttpClient HttpClient = new HttpClient(); 
    public ImgurAPI() 
    { 
     HttpClient.DefaultRequestHeaders.Add("Authorization", "Client-ID " + ClientId); 
    } 

    private async Task<HttpContent> doRequest(string urlQuery) 
    { 
     HttpResponseMessage response = await HttpClient.GetAsync(urlQuery); 
     return response.Content; 
    } 
    public HttpContent getImages(string search, int minSizeX, int minSizeY, string imageType, int page) 
    { 
     var url = BasicUri + "gallery/search/top/" + page.ToString() + "/"; 
     url += "?q=" + search; 
     Task<HttpContent> task = doRequest(url); 
     return task.Result; 
    } 
} 

Dass ich auf diese Weise nennen:

private void SearchImageClicked(object sender, RoutedEventArgs e) 
{ 
    HttpContent content = api.getImages(SearchBox.Text, 0, 0, "png", 1); 
    // other code here 
} 

Aber wenn getImages Rückkehr, mein Programm einfrieren. Ich setze einen Haltepunkt auf return task.Result; und es geht dahin. Aber ich stelle auch einen Breakpoint nach dem getImages Aufruf und es geht nicht dorthin, mein Programm einfrieren und ich muss den Prozess zu töten, damit es aufhören.

Wie ist es möglich?

Antwort

5

Dies liegt daran, dass Sie die Synchronisierung und async abmischen. Diese Linie führt zu einem Deadlock:

return task.Result; 

In doRequest, Sie verwenden await, die den aktuellen Synchronisationskontext erfasst (weil Sie nicht ConfigureAwait(false) angab Wenn HttpClient.GetAsync(urlQuery) abgeschlossen ist, versucht der Scheduler die Fortsetzung auf der laufen. Kontext, dh auf dem UI-Thread erfasst Aber die UI-Thread ist bereits besetzt warten doRequest zu vervollständigen, so dass die Fortsetzung in doRequest nicht ausgeführt werden kann.. einen Deadlock haben

Wenn Sie async/await verwenden, sollten Sie verwenden Es sollte den ganzen Weg, Sie sollten nicht Warten Sie synchron, bis eine asynchrone Methode abgeschlossen ist. In Ihrem Fall besteht die einfachste Lösung darin, auch getImages async zu machen und den konsumierenden Code async zu machen.

Weitere Informationen zu diesem Problem finden Sie unter this article von Stephen Cleary.

1

Wenn Sie task.Result anrufen, erzwingen Sie im Grunde, dass Ihr aufrufender Thread wartet, bis der andere Thread fertig ist.

Siehe Task.Result

1

Sowohl Ihre getImages und SearchImageClicked auch async sein muss.

public async Task<HttpContent> getImages(string search, int minSizeX, int minSizeY, string imageType, int page) 
{ 
    var url = BasicUri + "gallery/search/top/" + page.ToString() + "/"; 
    url += "?q=" + search; 
    return await doRequest(url); 
} 

und

private async void SearchImageClicked(object sender, RoutedEventArgs e) 
{ 
    HttpContent content = await api.getImages(SearchBox.Text, 0, 0, "png", 1); 
    // other code here 
} 
Verwandte Themen