C# assíncrono função de chamada de função síncrona síncrona ou de função de chamada de função async

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

Pergunta

Eu estou escrevendo um C# .Net 4.5 biblioteca para fazer comum sql operações de banco de dados (cópia de segurança, restaurar, executar o script, etc.).Eu quero ter tanto síncrona e assíncrona de funções para cada operação, como esta biblioteca vai ser utilizada pelo console e GUI apps, mas eu não quero código duplicado em todos os lugares.Então, como eu vejo, eu tenho duas opções:

  1. Escrever o código que faz o trabalho em uma função síncrona, e em seguida, envolvê-la em uma tarefa para a função async, assim:

    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. Escrever o código que faz o trabalho em uma função assíncrona, e chamá-lo a partir de uma função síncrona usando .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.  
    }
    

É uma opção melhor que o outro?É uma prática recomendada?Ou há alguma outra (melhor) alternativas?

Eu sei que um truque de usar .Wait() é que todos os aguardam instruções na função async tem que usar .ConfigureAwait(falso) para evitar deadlocks (como discutido aqui), mas desde que eu estou escrevendo uma biblioteca que nunca vai precisar acessar a INTERFACE de usuário ou WebContext eu estou seguro de fazer isso.

Eu vou note-se também que o SQL biblioteca normalmente também tem síncrona e assíncrona de funções que podem ser usadas, para se fazer o trabalho em função de sincronização, gostaria de chamar a sua função de sincronização, e se fazer o trabalho no assíncrona função, gostaria de chamar a sua função async.

Pensamentos/sugestões são bem-vindas.

-- edit:Eu também postou esta pergunta sobre os fóruns do MSDN aqui para tentar conseguir um oficial de MS de resposta --

Foi útil?

Solução

.

Eu quero ter funções síncronas e assíncronas para cada operação, pois esta biblioteca será usada pelos aplicativos do console e da GUI, mas eu não quero duplicar o código em todos os lugares.

A melhor resposta é: não.

Stephen Toub tem duas excelentes postagens de blog neste tópico:

Outras dicas

Eu tive uma situação semelhante, onde alguns aplicativos necessários os dados a serem carregados de forma síncrona e outros asyc.Eu decidi criada uma interface que eu chamei meu dataloader:

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

O AssignProjects de chamada de retorno é apenas um simples delegado que leva na lista retornada de projetos:

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

Agora, a beleza disso é que você pode trabalhar com a interface sem saber se você está dealling em sincronia ou assíncrona.

Três classes são criadas:uma base, um de sincronização, e um assíncrono:

 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);
    }

Agora, na sua aplicação, você pode decidir como você deseja carregar dados...isso pode ser injetado através de um contêiner IoC, mas é difícil codificado para fins de demonstração:

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

Agora, o código de chamada tem a mesma aparência e nenhum o mais sábio a se ele é assíncrono ou de sincronização:

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

Eu uso regularmente para o teste de unidade (sync), aplicativos do WPF (assíncrona), e aplicativos de console (sincronização).

Não parece ser um ponto para simplesmente marcar um método como assíncrono sem usar um aguardio. Marcando como assínco não o torna assíncrono, permite que você use aguarda (o código executado no aguardio é o que acontece de forma assíncrona e, em seguida, o resto do método assíncrono também será feito de forma assíncrona) no corpo do método: < / p >.

Normalmente, um método modificado pela palavra-chave assíncrona contém pelo menos um aguardam expressão ou declaração. O método é executado de forma síncrona até que atinja a primeira expressão aguardente, em que ponto ele é suspenso até que a tarefa aguardada esteja concluída. Enquanto isso, o controle é retornado ao chamador do método. Se o método não contiver uma expressão ou extrato aguardado, executa síncrona. Um aviso do compilador alerta você para qualquer método assíncrono que não contêm aguardam porque essa situação pode indicar um erro. Para mais informações, consulte o compilador Aviso CS4014.

de: Async < / p >.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top