Desempenho IPC: Named Pipe vs Socket

114

Todo mundo parece dizer que os pipes nomeados são mais rápidos do que os soquetes IPC. Eles são muito mais rápidos? Eu preferiria usar soquetes porque eles podem fazer comunicação bidirecional e são muito flexíveis, mas optarei pela velocidade em vez da flexibilidade se for em quantidade considerável.

user19745
fonte
10
Sua milhagem irá variar. :) Crie um perfil de uso típico para a aplicação pretendida e escolha o melhor dos dois. Em seguida, crie perfis de pipes anônimos, sockets de outros domínios e famílias, semáforos e memória compartilhada ou filas de mensagens (SysV e POSIX), sinais em tempo real com uma palavra de dados ou o que for. pipe(2)(er mkfifo(3),?) pode ser o vencedor, mas você não saberá até tentar.
pilcrow
2
Filas de mensagens SysV FTW! Não tenho ideia se eles são rápidos, só tenho uma queda por eles.
Tom Anderson
4
O que é "velocidade" neste caso? Taxa geral de transferência de dados? Ou latência (com que rapidez o primeiro byte chega ao receptor)? Se você deseja uma transferência local rápida de dados, é difícil superar a memória compartilhada. Se a latência for um problema, então a questão fica mais interessante ...
Ian Ni-Lewis

Respostas:

64

Eu sugeriria que você pegasse o caminho fácil primeiro, isolando cuidadosamente o mecanismo IPC para que você pudesse mudar de soquete para tubo, mas eu definitivamente escolheria primeiro com o soquete. Você deve ter certeza de que o desempenho do IPC é um problema antes de otimizar preventivamente.

E se você tiver problemas por causa da velocidade do IPC, acho que você deve considerar mudar para memória compartilhada em vez de canalizar.

Se você quiser fazer algum teste de velocidade de transferência, deve experimentar o socat , que é um programa muito versátil que permite criar quase qualquer tipo de túnel.

shodanex
fonte
47

Melhores resultados que você obterá com a solução de memória compartilhada .

Pipes nomeados são apenas 16% melhores do que soquetes TCP .

Os resultados são obtidos com o benchmarking IPC :

  • Sistema: Linux (Linux ubuntu 4.4.0 x86_64 i7-6700K 4,00 GHz)
  • Mensagem: 128 bytes
  • Contagem de mensagens: 1000000

Referência de tubo:

Message size:       128
Message count:      1000000
Total duration:     27367.454 ms
Average duration:   27.319 us
Minimum duration:   5.888 us
Maximum duration:   15763.712 us
Standard deviation: 26.664 us
Message rate:       36539 msg/s

Referência FIFOs (pipes nomeados):

Message size:       128
Message count:      1000000
Total duration:     38100.093 ms
Average duration:   38.025 us
Minimum duration:   6.656 us
Maximum duration:   27415.040 us
Standard deviation: 91.614 us
Message rate:       26246 msg/s

Comparativo de mercado do Message Queue:

Message size:       128
Message count:      1000000
Total duration:     14723.159 ms
Average duration:   14.675 us
Minimum duration:   3.840 us
Maximum duration:   17437.184 us
Standard deviation: 53.615 us
Message rate:       67920 msg/s

Referência de memória compartilhada:

Message size:       128
Message count:      1000000
Total duration:     261.650 ms
Average duration:   0.238 us
Minimum duration:   0.000 us
Maximum duration:   10092.032 us
Standard deviation: 22.095 us
Message rate:       3821893 msg/s

Referência de soquetes TCP:

Message size:       128
Message count:      1000000
Total duration:     44477.257 ms
Average duration:   44.391 us
Minimum duration:   11.520 us
Maximum duration:   15863.296 us
Standard deviation: 44.905 us
Message rate:       22483 msg/s

Comparativo de mercado de soquetes de domínio Unix:

Message size:       128
Message count:      1000000
Total duration:     24579.846 ms
Average duration:   24.531 us
Minimum duration:   2.560 us
Maximum duration:   15932.928 us
Standard deviation: 37.854 us
Message rate:       40683 msg/s

Referência ZeroMQ:

Message size:       128
Message count:      1000000
Total duration:     64872.327 ms
Average duration:   64.808 us
Minimum duration:   23.552 us
Maximum duration:   16443.392 us
Standard deviation: 133.483 us
Message rate:       15414 msg/s
cronoxor
fonte
1
Obrigado pelo benchmarking detalhado. Você quer dizer "multiprocessing.Queue" com "Message Queue"?
ovunccetina
1
Message Queue é uma fila de mensagens do sistema XSI ( man7.org/linux/man-pages/man0/sys_msg.h.0p.html )
chronoxor
34

Eu vou concordar com shodanex, parece que você está prematuramente tentando otimizar algo que ainda não é problemático. A menos que você saiba que os soquetes serão um gargalo, eu apenas os usaria.

Muitas pessoas que juram por pipes nomeados encontram um pouco de economia (dependendo de como tudo o mais está escrito), mas acabam com um código que passa mais tempo bloqueando uma resposta IPC do que fazendo um trabalho útil. Claro, esquemas sem bloqueio ajudam nisso, mas podem ser complicados. Passando anos trazendo códigos antigos para a era moderna, posso dizer que a aceleração é quase nula na maioria dos casos que vi.

Se você realmente acha que os soquetes vão atrasar você, então saia do portão usando a memória compartilhada com atenção cuidadosa em como você usa os bloqueios. Novamente, na realidade, você pode encontrar uma pequena aceleração, mas observe que está desperdiçando uma parte dela esperando bloqueios de exclusão mútua. Não vou defender uma viagem ao inferno do futex (bem, não exatamente mais o inferno em 2015, dependendo da sua experiência).

Libra por libra, os soquetes são (quase) sempre a melhor maneira de obter IPC de espaço do usuário em um kernel monolítico ... e (normalmente) a mais fácil de depurar e manter.

Tim Post
fonte
2
talvez algum dia em um futuro utópico distante tenhamos um kernel completamente novo, modular e moderno que implicitamente oferece todas as habilidades (interprocessos e outras) que atualmente caminhamos sobre vidros quebrados para realizar ... mas hey ... pode-se sonhar
Gukki5
27

Lembre-se de que soquetes não significam necessariamente IP (e TCP ou UDP). Você também pode usar soquetes UNIX (PF_UNIX), que oferecem uma melhoria de desempenho perceptível em relação à conexão com 127.0.0.1

Yuliy
fonte
1
E quanto ao Windows?
Pacerier
1
@Pacerier Infelizmente, você não pode criar sockets locais no Windows da mesma forma que o namespace abstrato no UNIX. Eu descobri que os soquetes PF_UNIX são substancialmente mais rápidos (> 10%) do que a maioria dos outros métodos descritos nesta página.
EntangledLoops
1
devblogs.microsoft.com/commandline/af_unix-comes-to-windows update, os soquetes Unix estão disponíveis no Windows 10 agora.
Eri0o
11

Se você não precisa de velocidade, os soquetes são o caminho mais fácil!

Se o que você está vendo é a velocidade, a solução mais rápida é a memória compartilhada, não os canais nomeados.

Damien
fonte
8

Para comunicação bidirecional com canais nomeados:

  • Se você tiver poucos processos, poderá abrir dois tubos para duas direções (processA2ProcessB e processB2ProcessA)
  • Se você tiver muitos processos, pode abrir canais de entrada e saída para cada processo (processAin, processAout, processBin, processBout, processCin, processCout etc)
  • Ou você pode ir híbrido como sempre :)

Pipes nomeados são muito fáceis de implementar.

Por exemplo, eu implementei um projeto em C com pipes nomeados, graças à comunicação baseada em entrada-saída de arquivo padrão (fopen, fprintf, fscanf ...) foi tão fácil e limpo (se isso também for uma consideração).

Até os codifiquei com java (estava serializando e enviando objetos sobre eles!)

Pipes nomeados têm uma desvantagem:

  • eles não escalam em vários computadores como soquetes, uma vez que dependem do sistema de arquivos (assumindo que o sistema de arquivos compartilhado não é uma opção)
daghan
fonte
8

Um problema com os soquetes é que eles não têm uma maneira de liberar o buffer. Existe algo chamado algoritmo de Nagle, que coleta todos os dados e os libera após 40 ms. Portanto, se for a capacidade de resposta e não a largura de banda, talvez seja melhor usar um tubo.

Você pode desabilitar o Nagle com a opção de socket TCP_NODELAY, mas o final da leitura nunca receberá duas mensagens curtas em uma única chamada de leitura.

Então teste, acabei sem nada disso e implementei filas baseadas em mapeamento de memória com pthread mutex e semáforo em memória compartilhada, evitando muitas chamadas de sistema do kernel (mas hoje elas não são mais lentas).

Lothar
fonte
3
"Então teste" <- palavras para viver.
Koshinae
6

Pipes e soquetes nomeados não são funcionalmente equivalentes; os soquetes fornecem mais recursos (eles são bidirecionais, para começar).

Não podemos dizer qual terá melhor desempenho, mas suspeito fortemente que não importa.

Os soquetes de domínio Unix farão praticamente o que os soquetes tcp farão, mas apenas na máquina local e com (talvez um pouco) menor sobrecarga.

Se um soquete Unix não for rápido o suficiente e você estiver transferindo muitos dados, considere o uso de memória compartilhada entre o cliente e o servidor (que é MUITO mais complicado de configurar).

Tanto o Unix quanto o NT têm "pipes nomeados", mas são totalmente diferentes no conjunto de recursos.

MarkR
fonte
1
Bem, se você abrir 2 tubos, também obterá comportamento bidi.
Pacerier
4

Você pode usar uma solução leve como ZeroMQ [ zmq / 0mq ]. É muito fácil de usar e muito mais rápido que os soquetes.

Amit Vujic
fonte
2
Você pode gostar, adivinha Amit, da próxima arte de Martin SUSTRIK - compatível com POSIX nanomsg. De qualquer forma, seja bem-vindo e aproveite este ótimo lugar e torne-se um membro contribuinte ativamente.
user3666197