Μπορεί κανείς να καλέσει ασύγχρονο κώδικα συγχρονικά;
sobes.tech AI
Απάντηση από AI
Ναι, είναι δυνατόν, αλλά μπορεί να προκαλέσει προβλήματα, ιδίως deadlocks.
Τρόποι κλήσης ασύγχρονου κώδικα με συγχρονικό τρόπο:
-
Χρήση της ιδιότητας
Resultή της μεθόδουWait()σε ένα αντικείμενοTask.// Συγχρονική κλήση μιας ασύγχρονης μεθόδου Task.Run(async () => await SomeAsyncTask()).Wait(); // Λήψη αποτελέσματος μιας ασύγχρονης μεθόδου συγχρονικά var result = SomeAsyncTaskWithResult().Result;async Task SomeAsyncTask() { await Task.Delay(100); } async Task<int> SomeAsyncTaskWithResult() { await Task.Delay(100); return 42; } -
Χρήση της
GetAwaiter().GetResult():// Συγχρονική κλήση μιας ασύγχρονης μεθόδου με λήψη αποτελέσματος var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
Μειονεκτήματα αυτής της προσέγγισης:
- Deadlock: Το πιο συνηθισμένο πρόβλημα, ειδικά σε UI νήματα ή σε περιβάλλοντα ASP.NET με συγχρονιστικό πλαίσιο. Το
Wait()και τοResultμπλοκάρουν το τρέχον νήμα, περιμένοντας την ολοκλήρωση της εργασίας. Αν η ασύγχρονη μέθοδος προσπαθεί να πιάσει το μπλοκαρισμένο πλαίσιο συγχρονισμού για να συνεχίσει μετά τοawait, προκύπτει deadlock. - Μείωση απόδοσης και κλιμάκωσης: Το μπλοκάρισμα νημάτων αντί να χρησιμοποιούνται ασύγχρονες λειτουργίες καταναλώνει περισσότερους πόρους και μειώνει την ικανότητα της εφαρμογής να χειρίζεται πολλαπλά αιτήματα ταυτόχρονα (π.χ., σε web εφαρμογές).
- Μη προφανής συμπεριφορά: Ο συνδυασμός ασύγχρονου και συγχρονου κώδικα μπορεί να κάνει τη ροή εκτέλεσης δύσκολη στην κατανόηση και αποσφαλμάτωση.
Στις περισσότερες περιπτώσεις, η σωστή προσέγγιση είναι η χρήση του await για την συνέχιση της ασύγχρονης εκτέλεσης ή, αν χρειάζεται να εκτελέσετε ασύγχρονο κώδικα στο σημείο εισόδου της εφαρμογής (π.χ., Main), η χρήση του Task.Run() σε συνδυασμό με Wait() ή η καθιστώντας το Main ασύγχρονο, αν η έκδοση C# το υποστηρίζει (async Task Main).
Παράδειγμα ασφαλούς κλήσης ασύγχρονου κώδικα από μια συγχρονική μέθοδο, χρησιμοποιώντας Task.Run για μεταφορά της εκτέλεσης στο pool νημάτων:
// Ασφαλής κλήση ασύγχρονης μεθόδου από συγχρονικό πλαίσιο
Task.Run(async () =>
{
await SomeAsyncTask();
}).Wait();
// Ασφαλής κλήση ασύγχρονης μεθόδου με αποτέλεσμα
var result = Task.Run(async () =>
{
return await SomeAsyncTaskWithResult();
}).Result;