C # avoir une fonction asynchrone d'appel de fonction synchrone ou fonctionnalité synchrone appeler fonction async

StackOverflow https://stackoverflow.com//questions/11674073

Question

J'écris une bibliothèque C # .NET 4.5 pour effectuer des opérations de base de données SQL communes (sauvegarde, restauration, script d'exécution, etc.). Je souhaite avoir des fonctions synchrones et asynchrones pour chaque opération, car cette bibliothèque sera utilisée à la fois par les applications de la console et de l'interface graphique, mais je ne veux pas dupliquer du code partout. Donc, comme je le vois, j'ai deux options:

  1. Écrivez le code qui fonctionne dans une fonction synchrone, puis il suffit de l'envelopper dans une tâche pour la fonction ASYNC, comme si:

    public void BackupDB(string server, string db)  
    {  
        // Do all of the work and long running operation here  
    }
    
    public async Task BackupDBAsync(string server, string db)  
    {  
        await Task.Factory.StartNew(() => BackupDB(server, db)).ConfigureAwait(false);  
    }
    

  2. Écrivez le code qui fonctionne dans une fonction asynchrone et l'appelez à partir d'une fonction synchrone à l'aide de .Wait ():

    public async Task BackupDBAsync(string server, string db)  
    {  
        // Do all of the work and long running operation here, asynchronously.  
    }
    
    public void BackupDB(string server, string db)  
    {  
        BackupDBAsync(server, db).Wait(); // Execution will wait here until async function finishes completely.  
    }
    

    est une option meilleure que l'autre? Est-une une bonne pratique? Ou y a-t-il d'autres (meilleures) alternatives?

    Je sais qu'une mise en garde à utiliser. Await () est que toutes les instructions attendues de la fonction ASYNC doivent utiliser .configureAwait (Faux) pour éviter les blocages ( Comme indiqué ici ), mais depuis que j'écris une bibliothèque qui n'aura jamais besoin d'accéder à l'interface utilisateur ou webcontext je suis sûr de le faire.

    Je vais noter que la bibliothèque SQL a généralement également des fonctions synchrones et asynchrones pouvant être utilisées, donc si vous effectuez la fonction de synchronisation de la fonction de synchronisation, j'appellerais leur fonction de synchronisation et si vous faites le travail dans l'ASYNC. Fonction, j'appellerais leur fonction asynchrone.

    Les pensées / suggestions sont appréciées.

    - Edit: J'ai aussi posté cette question sur les forums MSDN ici pour essayer de recevoir une réponse officielle de la SP -

Était-ce utile?

La solution

Je veux avoir des fonctions synchrones et asynchrones pour chaque opération, car cette bibliothèque sera utilisée à la fois par les applications de la console et de l'interface graphique, mais je ne veux pas dupliquer du code partout.

La meilleure réponse est: Ne pas.

Stephen Toub a deux excellents poteaux de blog sur ce sujet:

Autres conseils

J'ai eu une situation similaire dans laquelle certaines applications ont besoin des données à charger de manière synchrone et d'autres personnes ASYC.J'ai décidé de créer une interface que j'ai appelée mon dataloader:

public interface IIMViewModelDL {
    void LoadProjects(AssignProjects callback);
}

Le rappel mectProjects est juste un simple délégué qui prend la liste de projets retournés:

public delegate void AssignProjects(IEnumerable<Project> results);

Maintenant, la beauté de ceci est que vous pouvez travailler avec l'interface sans savoir si vous utilisez la synchronisation ou l'async.

Trois classes sont créées: une base, une synchronisation et une asynchronisation:

 public abstract class BaseViewModelDL {
    protected IEnumerable<Project> LoadProjects() {
        BaseServiceClient client = new BaseServiceClient();
        return client.Projects();
    }

public class SynchronousViewModelDL : BaseViewModelDL, IIMViewModelDL {
    public void LoadProjects(AssignProjects callback) {
        callback(base.LoadProjects());
    }

public class AsyncIMViewModelDL : BaseViewModelDL, IIMViewModelDL {
    public void LoadProjects(AssignProjects callback) {
        BackgroundWorker loadProjectsAsync = new BackgroundWorker();
        loadProjectsAsync.DoWork += new DoWorkEventHandler(LoadProjectsAsync_DoWork);
        loadProjectsAsync.RunWorkerCompleted += new RunWorkerCompletedEventHandler(LoadProjectsAsync_RunWorkerCompleted);
        loadProjectsAsync.RunWorkerAsync(callback);
    }

void LoadProjectsAsync_DoWork(object sender, DoWorkEventArgs e) {
        var results = new ObservableCollection<Project>(base.LoadProjects());
        e.Result = new object[] { results, e.Argument };
    }

    void LoadProjectsAsync_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        AssignProjects callback = (AssignProjects)((object[])e.Result)[1];
        IEnumerable<Project> results = (IEnumerable<Project>)((object[])e.Result)[0];
        callback(results);
    }

Maintenant, dans votre application, vous pouvez décider de la manière dont vous souhaitez charger des données ... Cela pourrait être injecté dans un conteneur COI, mais est codé dur à des fins de démonstration:

private ViewModelDataLoaders.IIMViewModelDL dataLoader = new ViewModelDataLoaders.AsyncIMViewModelDL();

Maintenant, votre code d'appel ressemble à la même chose et n'est pas plus sage de savoir s'il est async ou synchronisation:

private void LoadProjects() {
        dataLoader.LoadProjects(
            delegate(IEnumerable<Project> results) {
                Projects = new ObservableCollection<Project>(results);
            });
    }

Je l'utilise régulièrement pour les tests d'unités (Sync), les applications WPF (ASYNC) et les applications de console (Sync).

Il ne semble pas y avoir de point de marquer simplement une méthode comme ASYNC sans utiliser d'attendre. Le marquant comme ASYNC ne le rend pas asynchrone, il vous permet d'utiliser des attestements (le code exécuté dans l'attente est ce qui se passe de manière asynchrone, puis le reste de la méthode Async sera également fait de manière asynchrone) dans le corps de la méthode: < / p>

Typiquement, une méthode modifiée par le mot clé ASYNC contient au moins une expression ou une déclaration attendu. Le procédé fonctionne de manière synchrone jusqu'à ce qu'il atteigne la première expression attendue, à quel point il est suspendu jusqu'à la fin de la tâche attendue. Entre-temps, le contrôle est renvoyé à l'appelant de la méthode. Si la méthode ne contient pas d'expression ou de déclaration attendu, elle exécute de manière synchrone. Un avertissement de compilateur vous alerte à des méthodes asynchronisées qui ne contiennent pas d'attendre, car cette situation peut indiquer une erreur. Pour plus d'informations, voir Avertissement du compilateur CS4014.

de: async < / p>

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top