assíncrono vs sem bloqueio

373

Qual é a diferença entre chamadas assíncronas e sem bloqueio? Também entre chamadas bloqueadas e síncronas (com exemplos, por favor)?

user331561
fonte
4
Relacionados: stackoverflow.com/a/9489547/194894
Fluxo de
11
Eu tenho um bom entendimento sobre as diferenças ao ler o livro <Unix Networking Programação> Col 1, Capítulo 6.
Bin
2
Um artigo interessante: Aumente o desempenho do aplicativo usando E / S assíncrona . Ele categoriza os paradigmas de E / S em 4 categorias: (1) Bloqueio + Síncrono, (2) Não-Bloqueio + Síncrono, (3) Bloqueio + Assíncrono e (4) Não-Bloqueio + Assíncrono.
MS Dousti
@MSDousti Fui informado de que isso está errado de alguma forma, de um especialista do Google.
Rick
@MSDousti Depois de algum estudo, acho que não há combinação (3) e (2), como você descreve nos comentários. Verifique a definição de assíncrono, está falando sobre a mesma coisa de não-bloqueio. Como você pode ver a resposta principal, está confirmando minha opinião. A função de polling e retorno de chamada são apenas formas / padrões para implementar Assíncrono. Sim, estou dizendo que bloqueio, síncrono e não-bloqueio, assíncrono são 2 pares de sinônimos.
Rick

Respostas:

305

Em muitas circunstâncias, são nomes diferentes para a mesma coisa, mas em alguns contextos são bem diferentes. Então depende. A terminologia não é aplicada de maneira totalmente consistente em toda a indústria de software.

Por exemplo, na API de soquetes clássicos, um soquete sem bloqueio é aquele que simplesmente retorna imediatamente com uma mensagem de erro especial "bloquearia", enquanto um soquete de bloqueio teria bloqueado. Você precisa usar uma função separada, como selectou pollpara descobrir quando é um bom momento para tentar novamente.

Mas soquetes assíncronos (como suportados pelos soquetes do Windows), ou o padrão de E / S assíncrono usado no .NET, são mais convenientes. Você chama um método para iniciar uma operação, e a estrutura chama de volta quando terminar. Mesmo aqui, existem diferenças básicas. Os soquetes Win32 assíncronos "empacotam" seus resultados em um thread específico da GUI passando mensagens do Windows, enquanto o IO assíncrono do .NET é de thread livre (você não sabe em qual thread seu retorno de chamada será chamado).

Então eles nem sempre significam a mesma coisa. Para destilar o exemplo do soquete, poderíamos dizer:

  • Bloquear e síncrono significam a mesma coisa: você chama a API, ela desliga o encadeamento até ter algum tipo de resposta e a devolve.
  • Não bloquear significa que, se uma resposta não puder ser retornada rapidamente, a API retornará imediatamente com um erro e não fará mais nada. Portanto, deve haver alguma maneira relacionada de consultar se a API está pronta para ser chamada (ou seja, para simular uma espera de maneira eficiente, para evitar a pesquisa manual em um loop restrito).
  • Assíncrono significa que a API sempre retorna imediatamente, tendo iniciado um esforço "em segundo plano" para atender sua solicitação, portanto, deve haver alguma maneira relacionada de obter o resultado.
Daniel Earwicker
fonte
E / S de estado pronto em vez de E / S de estado de conclusão; no Linux, veja libaio
Will
4
Obrigado por apontar que os termos são sensíveis ao contexto e às vezes podem ser usados ​​de forma inconsistente. Acho especialmente na tecnologia, mas em outras áreas, que muitas vezes é mais útil reconhecer esse fato do que entrar em debates sobre qual definição precisa está correta, como às vezes acontece.
Chad NB
2
Acompanhamento P: A resposta parece fazer duas distinções diferentes entre os termos. Primeiro, a notificação: non-blocking implica que o aplicativo deve verificar novamente mais tarde (sondagem), enquanto o assíncrono implica que podemos esquecê-lo e confiar na estrutura / sistema operacional para nos notificar por meio de retorno de chamada ou postar um evento. Segundo, a ação: o não bloqueio não faz absolutamente nada além de retornar um erro, enquanto o assíncrono enfileira a ação ou a executa "em segundo plano" em algum sentido. Que diferença é mais importante na distinção dos termos? Existe alguma distinção mais fortemente associada a um termo? Ou é ambíguo?
Chad NB
2
@ChadNB - como termos, o não-bloqueio está fortemente associado à pesquisa. Com relação à questão de saber se a API "lembra" sua tentativa de chamá-la: o único motivo para a API se lembrar é para ligar de volta. Se você for chamá-lo para realizar uma nova pesquisa, então você já precisará manter o estado necessário para fazer a chamada subsequente, para que a API não agregue valor, mantendo também o estado.
precisa
6
Em vez de dizer que a chamada sem bloqueio retorna um "erro", acho que seria mais preciso dizer que uma chamada sem bloqueio faz o máximo que pode ser feito essencialmente imediatamente e indica o quanto fez. Para algumas operações, a quantidade de trabalho realizado será "tudo" ou "nada", mas algumas outras operações (como E / S de fluxo) podem retornar uma indicação quantitativa. O não bloqueio é semanticamente equivalente ao bloqueio com um tempo limite muito curto se a implementação de E / S de bloqueio permitir que uma operação que exceda o tempo limite seja repetida sem problemas mais tarde (alguns fazem; outros não).
supercat
56

síncrono / assíncrono é descrever a relação entre dois módulos.
bloqueio / não bloqueio é descrever a situação de um módulo.

Um exemplo:
Módulo X: "I".
Módulo Y: "livraria".
X pergunta a Y: você tem um livro chamado "c ++ primer"?

1) bloqueio: antes que Y responda X, X fica esperando lá pela resposta. Agora o X (um módulo) está bloqueando. X e Y são dois threads ou dois processos ou um thread ou um processo? nós não sabemos.

2) sem bloqueio: antes de Y responder X, X simplesmente sai de lá e faz outras coisas. X pode voltar a cada dois minutos para verificar se Y terminou seu trabalho? Ou X não voltará até que Y ligue para ele? Nós não sabemos. Sabemos apenas que X pode fazer outras coisas antes que Y termine seu trabalho. Aqui o X (um módulo) não é bloqueador. X e Y são dois threads ou dois processos ou um processo? nós não sabemos. MAS temos certeza de que X e Y não podem ser um segmento.

3) síncrona: antes de Y responder X, X fica esperando lá pela resposta. Isso significa que X não pode continuar até que Y termine seu trabalho. Agora dizemos: X e Y (dois módulos) são síncronos. X e Y são dois threads ou dois processos ou um thread ou um processo? nós não sabemos.

4) assíncrono: antes de Y responder X, X sai de lá e X pode fazer outros trabalhos. X não voltará até que Y ligue para ele. Agora dizemos: X e Y (dois módulos) são assíncronos. X e Y são dois threads ou dois processos ou um processo? nós não sabemos. MAS temos certeza de que X e Y não podem ser um segmento.


Por favor, preste atenção nas duas frases em negrito acima. Por que a frase em negrito no 2) contém dois casos, enquanto a frase em negrito no 4) contém apenas um caso? Essa é a chave da diferença entre não-bloqueio e assíncrona.

Aqui está um exemplo típico de não-bloqueio e síncrono:

// thread X
while (true)
{
    msg = recv(Y, NON_BLOCKING_FLAG);
    if (msg is not empty)
    {
        break;
    }
    sleep(2000); // 2 sec
}

// thread Y
// prepare the book for X
send(X, book);

Você pode ver que esse design é sem bloqueio (você pode dizer que na maioria das vezes esse loop faz algo sem sentido, mas aos olhos da CPU, X está em execução, o que significa que X não é bloqueador) enquanto X e Y são síncronos porque X pode continue fazendo outras coisas (X não pode pular para fora do loop) até que ele receba o livro de Y.
Normalmente, nesse caso, o bloqueio do X é muito melhor porque o não bloqueio gasta muito recurso para um loop estúpido. Mas este exemplo é bom para ajudá-lo a entender o fato: não-bloquear não significa assíncrono.

As quatro palavras nos confundem facilmente, o que devemos lembrar é que as quatro palavras servem para o design da arquitetura. Aprender sobre como projetar uma boa arquitetura é a única maneira de distingui-las.

Por exemplo, podemos projetar esse tipo de arquitetura:

// Module X = Module X1 + Module X2
// Module X1
while (true)
{
    msg = recv(many_other_modules, NON_BLOCKING_FLAG);
    if (msg is not null)
    {
        if (msg == "done")
        {
            break;
        }
        // create a thread to process msg
    }
    sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");


// Module Y
// prepare the book for X
send(X, book);

No exemplo aqui, podemos dizer que

  • X1 é sem bloqueio
  • X1 e X2 são síncronos
  • X e Y são assíncronos

Se precisar, também é possível descrever os threads criados no X1 com as quatro palavras.

As coisas mais importantes são: quando usamos síncrona em vez de assíncrona? quando usamos bloqueio em vez de não-bloqueio?

Por que o Nginx é sem bloqueio? Por que o Apache está bloqueando?

Para fazer uma boa escolha, você deve analisar sua necessidade e testar o desempenho de diferentes arquiteturas. Não existe uma arquitetura adequada para várias necessidades.

Yves
fonte
7
A IMO é a melhor resposta, pois captura a essência do conceito: a relação entre um ou dois participantes.
Fábio
em 1 e 3, Y está atuando como um recurso LIMITADO. Não há mais Y's para ajudar X
UVM
46
  • Assíncrono refere-se a algo feito em paralelo , digamos, é outro segmento.
  • O não-bloqueio geralmente se refere à pesquisa , ou seja, verificar se uma condição é válida (o soquete é legível, o dispositivo possui mais dados, etc.)
Nikolai Fetissov
fonte
17
quando a E / S está envolvida, geralmente assíncrona não está "em paralelo", nem "outro encadeamento", principalmente baseada em notificações. isto é: não bloqueie, não faça pesquisas, apenas receba o sinal. Claro, pode-se argumentar que o sinal é proveniente do 'mundo real' que pode ser pensado como 'outro segmento' ...
Javier
Bem, sim, nós podemos discutir a formulação exata durante todo o dia :)
Nikolai Fetissov
mas como você explica a AIO no Linux? que usou o Async e o não-bloqueio. AIO LINKS
Djvu
16
Para quem está lendo esta resposta: isso não está discutindo sobre o texto exato. Do mesmo modo que concorrência e paralelismo não são as mesmas noções, e distingui-las não é um problema de redação. Assincronicidade e paralelismo são dois animais diferentes e essa resposta imprecisa os torna iguais.
Ptival 8/08/16
2
O assíncrono não significa necessariamente que é feito em paralelo; veja este ótimo post no stackoverflow sobre programação simultânea e paralela.
BARJ 27/10
17

Colocando essa questão no contexto da NIO e da NIO.2 no java 7, a E / S assíncrona é um passo mais avançado que o não-bloqueio. Com chamadas NIO sem bloqueio de java, seria possível definir todos os canais (SocketChannel, ServerSocketChannel, FileChannel, etc.) como tal, chamando AbstractSelectableChannel.configureBlocking(false). Após o retorno dessas chamadas de E / S, no entanto, você provavelmente ainda precisará controlar as verificações, como se e quando ler / gravar novamente etc.
Por exemplo,

while (!isDataEnough()) {
    socketchannel.read(inputBuffer);
    // do something else and then read again
}

Com a API assíncrona no java 7, esses controles podem ser feitos de maneiras mais versáteis. Uma das 2 maneiras é usar CompletionHandler. Observe que as duas readchamadas são sem bloqueio.

asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */, 
    new CompletionHandler<Integer, Object>() {
        public void completed(Integer result, Object attachment) {...}  
        public void failed(Throwable e, Object attachment) {...}
    }
}
Anthony
fonte
3
FileChannelnão é selecionável e não pode ser configurado para não bloquear.
22614 michaelliu
15

Como você provavelmente pode ver da multiplicidade de respostas diferentes (e muitas vezes mutuamente exclusivas), depende de quem você perguntar. Em algumas arenas, os termos são sinônimos. Ou eles podem se referir a dois conceitos semelhantes:

  • Uma interpretação é que a chamada fará algo em segundo plano essencialmente não supervisionado, a fim de permitir que o programa não seja sustentado por um processo demorado que ele não precisa controlar. A reprodução de áudio pode ser um exemplo - um programa pode chamar uma função para reproduzir (digamos) um mp3 e, a partir desse momento, continuar com outras coisas, deixando o sistema operacional para gerenciar o processo de renderização do áudio no hardware de som .
  • A interpretação alternativa é que a chamada fará algo que o programa precisará monitorar, mas permitirá que a maior parte do processo ocorra em segundo plano, notificando-o apenas em pontos críticos do processo. Por exemplo, E / S de arquivo assíncrono pode ser um exemplo - o programa fornece um buffer ao sistema operacional para gravar no arquivo, e o SO só notifica o programa quando a operação estiver concluída ou ocorrer um erro.

Em ambos os casos, a intenção é permitir que o programa não seja bloqueado, aguardando a conclusão de um processo lento - a expectativa de resposta do programa é a única diferença real. Qual termo refere-se ao qual também muda de programador para programador, idioma para idioma ou plataforma para plataforma. Ou os termos podem se referir a conceitos completamente diferentes (como o uso de síncrono / assíncrono em relação à programação de threads).

Desculpe, mas não acredito que exista uma única resposta certa que seja globalmente verdadeira.

Mac
fonte
11
+1 boa resposta. As pessoas precisam estar cientes de que "assíncrona" pode significar tanto non-blocking, ou a abordagem asynch Microsoft (baseado em evento / callback).
Engenheiro
14

Uma chamada sem bloqueio retorna imediatamente com os dados disponíveis: o número total de bytes solicitados, menos ou nenhum.

Uma chamada assíncrona solicita uma transferência que será executada em sua totalidade (totalidade), mas será concluída em algum momento futuro.

Koray Tugay
fonte
non-blocking não retorna nenhum resultado
CEO da Apartico em 9/10/19
9

Sem bloqueio: Esta função não espera enquanto estiver na pilha.

Assíncrono: o trabalho pode continuar em nome da chamada de função após a saída da pilha

Frank Schwieterman
fonte
11
@Marenz significa que você não pode executar io sem bloqueio diretamente com chamadas posix. Isso não muda o significado que ele dá aqui.
21411
@Marenz O que significa apenas que o sinalizador é ignorado para arquivos. Não afeta o significado desta resposta.
Marquês de Lorne #
8

Síncrono é definido como acontecendo ao mesmo tempo.

Assíncrono é definido como não acontecendo ao mesmo tempo.

É isso que causa a primeira confusão. Síncrono é realmente o que é conhecido como paralelo. Enquanto assíncrono é seqüencial, faça isso e faça isso.

Agora, todo o problema é modelar um comportamento assíncrono, porque você tem alguma operação que precisa da resposta de outra antes que ela possa começar. Portanto, é um problema de coordenação. Como você saberá que agora pode iniciar essa operação?

A solução mais simples é conhecida como bloqueio.

O bloqueio ocorre quando você simplesmente decide esperar pela outra coisa e devolve uma resposta antes de prosseguir para a operação que precisava.

Portanto, se você precisar colocar manteiga na torrada, primeiro precisará torrar a raça. A maneira como você os coordenava é que você primeiro brindava a raça, depois olhava sem parar a torradeira até que ela aparecesse, e então você passava a manteiga nelas.

É a solução mais simples e funciona muito bem. Não há motivo real para não usá-lo, a menos que você tenha outras coisas que precisam ser executadas que não exijam coordenação com as operações. Por exemplo, lavando a louça. Por que esperar ocioso olhando a torradeira constantemente para a torrada estourar, quando você sabe que vai demorar um pouco e pode lavar um prato inteiro enquanto ela termina?

É aí que duas outras soluções conhecidas respectivamente como não bloqueadoras e assíncronas entram em cena.

Não-bloqueio é quando você escolhe fazer outras coisas não relacionadas enquanto espera a execução da operação. Verifique novamente a disponibilidade da resposta como achar melhor.

Então, ao invés de olhar para a torradeira, ela aparece. Você vai e lava um prato inteiro. E então você espia a torradeira para ver se as torradas estalaram. Se não tiverem, você vai lavar outro prato, verificando novamente a torradeira entre cada prato. Quando você vê que as torradas estalaram, você para de lavar a louça e, em vez disso, pega a torrada e passa a colocar manteiga nelas.

Ter que verificar constantemente as torradas pode ser irritante, imagine que a torradeira esteja em outra sala. Entre os pratos, você perde seu tempo indo para a outra sala para conferir a torrada.

Aí vem assíncrono.

Assíncrono é quando você escolhe fazer outras coisas não relacionadas enquanto aguarda a conclusão da operação. Em vez de verificar isso, você delega o trabalho de verificação para outra coisa, pode ser a operação em si ou um observador, e você deve notificar e possivelmente interromper você quando a resposta estiver disponível, para que você possa prosseguir para a outra operação que precisava disso.

É uma terminologia estranha. Não faz muito sentido, pois todas essas soluções são maneiras de criar coordenação assíncrona de tarefas dependentes. É por isso que prefiro chamá-lo de evento.

Portanto, para este, você decide atualizar sua torradeira para que apite quando as torradas terminarem. Você está constantemente ouvindo, mesmo enquanto lava a louça. Ao ouvir o sinal sonoro, você coloca em fila na memória que, assim que terminar de lavar o prato atual, vai parar e colocar a manteiga na torrada. Ou você pode optar por interromper a lavagem do prato atual e lidar com a torrada imediatamente.

Se você tiver problemas para ouvir o sinal sonoro, peça para o seu parceiro assistir a torradeira e avisar quando a torrada estiver pronta. O seu parceiro pode escolher qualquer uma das três estratégias acima para coordenar sua tarefa de assistir à torradeira e dizer quando está pronta.

Em uma nota final, é bom entender que, apesar de não-bloqueio e assíncrono (ou o que eu prefiro chamar de evento) permitem que você faça outras coisas enquanto espera, mas também não. Você pode optar por verificar constantemente o status de uma chamada sem bloqueio, sem fazer mais nada. No entanto, muitas vezes é pior do que bloquear (como olhar para a torradeira, depois para longe e depois para trás até que esteja pronto); portanto, muitas APIs sem bloqueio permitem que você faça a transição para um modo de bloqueio. Para eventos, você pode apenas esperar inativo até ser notificado. A desvantagem nesse caso é que adicionar a notificação era complexo e potencialmente caro para começar. Você precisou comprar uma nova torradeira com funcionalidade de bipe ou convencer seu parceiro a assistir por você.

E mais uma coisa, você precisa perceber as vantagens e desvantagens que os três oferecem. Um não é obviamente melhor que os outros. Pense no meu exemplo. Se a sua torradeira for tão rápida, você não terá tempo para lavar a louça, nem mesmo começar a lavá-la, é a velocidade da torradeira. Começar outra coisa nesse caso é apenas uma perda de tempo e esforço. O bloqueio serve. Da mesma forma, se lavar um prato demorar 10 vezes mais do que a torrada. Você precisa se perguntar o que é mais importante a ser feito? A torrada pode ficar fria e dura a essa altura, não vale a pena, o bloqueio também serve. Ou você deve escolher coisas mais rápidas para fazer enquanto espera. É mais óbvio, mas minha resposta já é bastante longa, o que quero dizer é que você precisa pensar sobre tudo isso e as complexidades de implementar cada uma para decidir se vale a pena e se vale a pena.

Editar:

Mesmo que isso já seja longo, também quero que esteja completo, então adicionarei mais dois pontos.

1) Também existe geralmente um quarto modelo conhecido como multiplexado . É quando você espera por uma tarefa, inicia outra e, enquanto espera pelas duas, inicia mais uma e assim por diante, até ter muitas tarefas iniciadas e depois esperar inativo, mas em todas eles. Assim que tudo estiver pronto, você poderá prosseguir com o tratamento da resposta e voltar a esperar pelos outros. É conhecido como multiplexado, porque enquanto você espera, você precisa verificar cada tarefa uma após a outra para ver se elas foram concluídas, ad vitam, até que uma seja. É um pouco de uma extensão além do normal, sem bloqueio.

No nosso exemplo, seria como iniciar a torradeira, a máquina de lavar louça, o micro-ondas, etc. E então esperar por uma delas. Onde você verificaria a torradeira para ver se está pronto; caso contrário, verificaria a máquina de lavar louça, se não estiver, o micro-ondas e o ambiente novamente.

2) Embora eu acredite que seja um grande erro, síncrono é frequentemente usado para significar uma coisa de cada vez. E assíncrono muitas coisas ao mesmo tempo. Assim, você verá o bloqueio síncrono e o não-bloqueio usados ​​para se referir a bloqueio e não-bloqueio. E bloqueio assíncrono e sem bloqueio costumavam se referir a multiplexados e a eventos.

Eu realmente não entendo como chegamos lá. Mas quando se trata de E / S e computação, síncrono e assíncrono geralmente se referem ao que é mais conhecido como não sobreposto e sobreposto. Ou seja, assíncrono significa que IO e Computação estão sobrepostas, ou seja, acontecendo simultaneamente. Enquanto síncrono significa que não, isso acontece sequencialmente. Para o não-bloqueio síncrono, isso significa que você não inicia outro IO ou computação, apenas espera e simula uma chamada de bloqueio. Eu gostaria que as pessoas parassem de usar síncrona e assíncrona assim. Então, eu não estou encorajando isso.

Didier A.
fonte
Não sabe por que você disse "Síncrono é definido como acontecendo ao mesmo tempo". A idéia toda é que não é simultânea, ou seja, não está acontecendo ao mesmo tempo.
Helsing
Foi uma ótima analogia! Você apenas brindou!
d-coder
@Helsing Isso é literalmente o que a palavra significa. Síncrono significa a mesma hora e assíncrono significa a mesma hora: p. A razão pela qual algo é assíncrono, é porque não pode acontecer ao mesmo tempo, deve acontecer antes ou depois. Se isso acontecesse ao mesmo tempo, você poderia simplesmente paralelá-lo ou fazê-lo em qualquer ordem e não precisaria de sincronização explícita. É por isso que a programação assíncrona tem a ver com fazer isso; depois, espere por essas coisas e depois, etc. Porque nenhuma dessas coisas pode acontecer juntas ao mesmo tempo.
Didier A.
@Helsing Além disso, simultâneo não é o mesmo que paralelo. Isso não significa que duas coisas estão acontecendo ao mesmo tempo, apenas significa progresso em mais de uma coisa antes que qualquer uma delas termine. Isso poderia ser realizado com paralelização, ou simplesmente com intercalação, também conhecida como troca de tarefas.
Didier A.
5

Bloqueio de chamada: o controle retorna somente quando a chamada é concluída.

Chamada sem bloqueio : o controle retorna imediatamente. O SO posterior, de alguma forma, notifica o processo de que a chamada está concluída.


Programa síncrono : um programa que usa o bloqueio de chamadas. Para não congelar durante a chamada, ele deve ter 2 ou mais threads (é por isso que é chamado Synchronous - os threads estão em execução de forma síncrona).

Programa assíncrono : um programa que usa chamadas não bloqueadas . Ele pode ter apenas 1 thread e ainda permanecer interativo.

Babken Vardanyan
fonte
11
Chamada sem bloqueio: o controle retorna depois de fazer o máximo que pode ser feito essencialmente imediatamente; o método indica quanto foi feito. Isso é diferente de uma chamada assíncrona, que se comporta como você descreveu para bloquear uma chamada.
Supercat
0

Eles diferem apenas na ortografia. Não há diferença no que eles se referem. Para ser técnico, você poderia dizer que eles diferem em ênfase. Não-bloqueio refere-se ao fluxo de controle (não é bloqueado.) Assíncrono refere-se a quando o evento \ data é tratado (não de forma síncrona).

pedregoso
fonte
0

Os modelos de bloqueio exigem que o aplicativo inicial seja bloqueado quando a E / S for iniciada. Isso significa que não é possível sobrepor processamento e E / S ao mesmo tempo. O modelo síncrono sem bloqueio permite sobreposição de processamento e E / S, mas requer que o aplicativo verifique o status da E / S de forma recorrente. Isso deixa E / S sem bloqueio assíncrona, que permite sobreposição de processamento e E / S, incluindo notificação de conclusão de E / S.

P.Gurung
fonte
-2

Bloqueio: o controle retorna para invocar a precess após o processamento do primitivo (sincronização ou assíncrona)

Sem bloqueio: o controle retorna ao processo imediatamente após a chamada

Moslema
fonte
10
Isso nem responde ao que está sendo solicitado.
Koray Tugay