GPT async, await i aplikacja okienkowa

GPT async, await i aplikacja okienkowa
PA
  • Rejestracja:ponad 9 lat
  • Ostatnio:około 2 lata
  • Postów:21
0

Hej

Napotkałem taki problem z aplikacją którą popełniłem lata temu, a służyła mi do uzupełniania opisów produktowych w jakiejś tam bazie systemu epr. Aplikacja klasyczna windows forms, .net Framework 4.8.
Chciałem uprościć pracę i dorzucić generowanie tekstów z gpt, i mam problem taki, że tam gdzie robię await - aplikacja mi się zamraża :)
Dochodze do tej liniki gdzie jest await i cisza...

To samo w konsolowej chodzi i odpowiada.
Dlaczego tak się dzieje? Co i gdzie zgubiłem?

Kopiuj
private void btn_gpt(object sender, EventArgs e)
{
    Task<string> task = Obsluga.SendChatGTPRequest(txt_gpt_question.Text, "sk-xxxxx");
    if (task != null)
    {
        txt_response.Text = task.Result;
    }
}
Kopiuj
public async static Task<string> SendChatGTPRequest(string question, string apiKey)
{
...
using (var httpReq = new HttpRequestMessage(HttpMethod.Post, "https://api.openai.com/v1/completions"))
            {
                httpReq.Headers.Add("Authorization", $"Bearer {apiKey}");
                string requestString = JsonSerializer.Serialize(completionRequest);
                httpReq.Content = new StringContent(requestString, Encoding.UTF8, "application/json");

                using (HttpResponseMessage httpResponse = await httpClient.SendAsync(httpReq))
                {
                    if (httpResponse != null)
                    {
                        string responseString = await httpResponse.Content.ReadAsStringAsync();
                        if (httpResponse.IsSuccessStatusCode && !string.IsNullOrWhiteSpace(responseString))
                        {
                            completionResponse = JsonSerializer.Deserialize<CompletionResponse>(responseString);
                        }
                    }
                }
            }
...
}

PA
  • Rejestracja:ponad 9 lat
  • Ostatnio:około 2 lata
  • Postów:21
0

Ej dobra, już sobie rozwiązałem xD

Patryk27
Jakaś podpowiedź może się mimo wszystko przydać osobom, które mogą natrafić na ten wątek w przyszłości :-P
obscurity
błędem było zapewne użycie task.Result. Nie używaj nigdy task.Result, blokujesz wątek w oczekiwaniu na odpowiedź i potem jakikolwiek await wewnątrz próbujący wrócić do kontekstu tego wątku nie może bo jest zablokowany i masz deadlock. Można to ominąć przez .ConfigureAwait(false) ale lepiej oczekiwać na taska w inny sposób, a najlepiej jak kod jest asynchroniczny aż do maina
lukaszek016
@obscurity: .ConfigureAwait(false) w teorii mogłoby pomóc, ale spowodowałoby utracenie oryginalnego kontekstu i przypisanie do kontrolki pewnie wywaliłoby wyjątek.
obscurity
no nie bo jeśli ConfigureAwait jest wewnątrz metody a później awaitujemy normalnie w kodzie związanym z kontrolką to i tak wracamy do kontekstu
lukaszek016
A jak wewnątrz to faktycznie. Myślałem, że masz na myśli użycie na zewnątrz, ale to chyba i tak by nie działało tak jak napisałem.
PA
  • Rejestracja:ponad 9 lat
  • Ostatnio:około 2 lata
  • Postów:21
0

@obscurity: do taks.Result nie dochodziło, SendChatGTPRequest() nie zwracał nic

Zmieniłem

Kopiuj
Task<string> task = Obsluga.SendChatGTPRequest(txt_gpt_question.Text, "sk-xxxxx");
na
var result = await Task.Run(() => Obsluga.SendChatGTPRequest(txt_gpt_question.Text, "sk-xxxxx"));
lukaszek016
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad rok
  • Postów:249
0

Dlaczego nie zrobisz awaita na wywołaniu metody Obsluga.SendChatGTPRequest
i nie przypiszesz wyniku do zmiennej typu string zamiast Task tylko tworzysz takie dziwne konstrukcje?

edytowany 1x, ostatnio: lukaszek016
PA
  • Rejestracja:ponad 9 lat
  • Ostatnio:około 2 lata
  • Postów:21
0
lukaszek016 napisał(a):

Dlaczego nie zrobisz awaita na wywołaniu metody Obsluga.SendChatGTPRequest
i nie przypiszesz wyniku do zmiennej typu string zamiast Task tylko tworzysz takie dziwne konstrukcje?

No właśnie nie wiem, ja to w tak podstawowym zakresie coś umiem, poprawiłem na chyba poprawnie :)
A jak powinno być wg Ciebie?

JE
  • Rejestracja:około 4 lata
  • Ostatnio:12 dni
  • Postów:7
2

Zamiast robić

Kopiuj
var result = await Task.Run(() => Obsluga.SendChatGTPRequest(txt_gpt_question.Text, "sk-xxxxx"));

bo generalnie to generuje pod spodem jak i w kodzie nie potrzebnie dodatkową ilość kodu i zwyczajnie brzydko wygląda, bo robisz dwa razy to samo
to zrób tak:

Kopiuj
var result = await Obsluga.SendChatGTPRequest(txt_gpt_question.Text, "sk-xxxxx");

jako, że twoja metoda zwraca Taska to możesz ją zawaitować

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.