Qual é a diferença entre um fio e uma fibra?

187

Qual é a diferença entre um fio e uma fibra? Já ouvi falar de fibras de rubi e li que elas estão disponíveis em outros idiomas. Alguém poderia me explicar em termos simples qual é a diferença entre um fio e uma fibra.

tatsuhirosatou
fonte

Respostas:

163

Nos termos mais simples, os encadeamentos geralmente são considerados preemptivos (embora isso nem sempre seja verdade, dependendo do sistema operacional), enquanto as fibras são consideradas encadeamentos cooperativos leves. Ambos são caminhos de execução separados para o seu aplicativo.

Com threads: o caminho de execução atual pode ser interrompido ou antecipado a qualquer momento (nota: esta declaração é uma generalização e nem sempre é verdadeira, dependendo do pacote do OS / threading / etc.). Isso significa que, para os encadeamentos, a integridade dos dados é um grande problema, pois um encadeamento pode ser interrompido no meio da atualização de um pedaço de dados, deixando a integridade dos dados em um estado incorreto ou incompleto. Isso também significa que o sistema operacional pode tirar proveito de várias CPUs e núcleos de CPU executando mais de um encadeamento ao mesmo tempo e deixando ao desenvolvedor a responsabilidade de proteger o acesso aos dados.

Com fibras: o caminho de execução atual é interrompido apenas quando a fibra produz execução (mesma nota acima). Isso significa que as fibras sempre iniciam e param em locais bem definidos; portanto, a integridade dos dados é muito menos um problema. Além disso, como as fibras geralmente são gerenciadas no espaço do usuário, não é necessário fazer comutações de contexto caras e alterações no estado da CPU, tornando extremamente eficiente a alteração de uma fibra para a seguinte. Por outro lado, como duas fibras não podem ser executadas exatamente ao mesmo tempo, apenas o uso de fibras por si só não tirará vantagem de várias CPUs ou múltiplos núcleos de CPU.

Jason Coco
fonte
7
Existe alguma maneira de usar vários threads para executar fibras em paralelo?
Baradé 07/04
2
@ Jason, Quando você declara ~ "com fibras, o caminho de execução atual só é interrompido quando a fibra produz execução" e "as fibras sempre iniciam e param em locais bem definidos, para que a integridade dos dados seja muito menos problemática", você quer dizer que ao compartilhar variáveis, não precisamos usar "mecanismos de bloqueio" e variáveis ​​voláteis? Ou você quer dizer que ainda precisamos fazer essas coisas?
Pacerier 18/06/2015
@ Baradé É uma pergunta interessante, você encontrou uma resposta?
Mayur
57

Os encadeamentos usam agendamento preventivo , enquanto as fibras usam agendamento cooperativo .

Com um thread, o fluxo de controle pode ser interrompido a qualquer momento e outro thread pode assumir o controle. Com vários processadores, você pode ter vários threads em execução ao mesmo tempo ( multithreading simultâneo ou SMT). Como resultado, você deve ter muito cuidado com o acesso simultâneo a dados e proteger seus dados com mutexes, semáforos, variáveis ​​de condição e assim por diante. Muitas vezes, é muito complicado acertar.

Com uma fibra, o controle somente alterna quando você solicita, normalmente com uma chamada de função chamada algo como yield(). Isso facilita o acesso simultâneo a dados, pois você não precisa se preocupar com a atomicidade das estruturas ou mutexes de dados. Contanto que você não ceda, não há perigo de ser antecipado e ter outra fibra tentando ler ou modificar os dados com os quais você está trabalhando. Como resultado, porém, se sua fibra entrar em um loop infinito, nenhuma outra fibra poderá funcionar, pois você não está cedendo.

Você também pode misturar fios e fibras, o que dá origem aos problemas enfrentados por ambos. Não recomendado, mas às vezes pode ser a coisa certa a ser feita se for feita com cuidado.

Adam Rosenfield
fonte
3
Eu acho que um loop infinito é apenas um bug que precisa ser corrigido, e os threads só têm uma vantagem bastante obscura quando há um loop infinito. O conceito não relacionado ao buggy é quando existe um processo de execução demorada que o usuário pode cancelar. Nesse caso, se você usa threads ou fibras, o processo de longa execução precisa ser cooperativo - apenas matar seu thread pode deixar algumas estruturas de dados desarrumadas; portanto, uma maneira melhor é, por exemplo, que o processo de longa execução verifique periodicamente se tivesse sido interrompido. Isso não é muito diferente de uma fibra que produz periodicamente.
Evgeni Sergeev #
43

No Win32, uma fibra é uma espécie de thread gerenciado pelo usuário. Uma fibra tem sua própria pilha e seu próprio ponteiro de instruções, etc., mas as fibras não são agendadas pelo sistema operacional: você precisa chamar o SwitchToFiber explicitamente. Os encadeamentos, por outro lado, são agendados preventivamente pelo sistema operacional. Então, grosso modo, uma fibra é um encadeamento que é gerenciado no nível do aplicativo / tempo de execução, em vez de ser um encadeamento verdadeiro do SO.

As conseqüências são que as fibras são mais baratas e que o aplicativo tem mais controle sobre o agendamento. Isso pode ser importante se o aplicativo criar muitas tarefas simultâneas e / ou desejar otimizar de perto quando elas forem executadas. Por exemplo, um servidor de banco de dados pode optar por usar fibras em vez de threads.

(Pode haver outros usos para o mesmo termo; conforme observado, esta é a definição do Win32.)

Itowlson
fonte
37

Primeiro, eu recomendaria ler esta explicação da diferença entre processos e threads como material de base.

Depois de ler, é bem direto. As latas de threads podem ser implementadas no kernel, no espaço do usuário ou as duas podem ser misturadas. As fibras são basicamente threads implementadas no espaço do usuário.

  • O que normalmente é chamado de thread é um thread de execução implementado no kernel: o que é conhecido como thread do kernel. O agendamento de um thread do kernel é tratado exclusivamente pelo kernel, embora um thread do kernel possa liberar voluntariamente a CPU dormindo se desejar. Um encadeamento do kernel tem a vantagem de poder usar E / S de bloqueio e deixar o kernel se preocupar com o agendamento. Sua principal desvantagem é que a troca de threads é relativamente lenta, pois requer interceptação no kernel.
  • Fibras são encadeamentos do espaço do usuário cujo agendamento é tratado no espaço do usuário por um ou mais encadeamentos do kernel em um único processo. Isso torna a troca de fibra muito rápida. Se você agrupar todas as fibras que acessam um conjunto específico de dados compartilhados no contexto de um único thread do kernel e tiver seu agendamento tratado por um único thread do kernel, poderá eliminar os problemas de sincronização, pois as fibras serão efetivamente executadas em série e você terá concluído controle sobre sua programação. O agrupamento de fibras relacionadas em um único encadeamento do kernel é importante, pois o encadeamento do kernel em que estão executando pode ser antecipado pelo kernel. Este ponto não está claro em muitas das outras respostas. Além disso, se você usar E / S de bloqueio em uma fibra, todo o thread do kernel fará parte dos blocos, incluindo todas as fibras que fazem parte desse thread do kernel.

Na seção 11.4 "Processos e threads no Windows Vista" em sistemas operacionais modernos, Tanenbaum comenta:

Embora as fibras sejam agendadas cooperativamente, se houver vários encadeamentos agendando as fibras, será necessária muita sincronização cuidadosa para garantir que as fibras não interfiram entre si. Para simplificar a interação entre threads e fibras, geralmente é útil criar apenas quantos threads houver processadores para executá-los e afinitar os threads para cada execução apenas em um conjunto distinto de processadores disponíveis, ou mesmo em apenas um processador. Cada encadeamento pode executar um subconjunto específico das fibras, estabelecendo uma relação de muitos entre encadeamentos e fibras, o que simplifica a sincronização. Mesmo assim, ainda existem muitas dificuldades com as fibras. A maioria das bibliotecas Win32 não tem conhecimento de fibras, e os aplicativos que tentam usar fibras como se fossem threads encontrarão várias falhas. O kernel não tem conhecimento de fibras e, quando uma fibra entra no kernel, o encadeamento em execução pode bloquear e o kernel agendará um encadeamento arbitrário no processador, tornando-o indisponível para executar outras fibras. Por esses motivos, as fibras raramente são usadas, exceto ao transportar código de outros sistemas que precisam explicitamente da funcionalidade fornecida pelas fibras.

Robert S. Barnes
fonte
4
Essa é a resposta mais completa.
Bernard
12

Observe que, além de threads e fibras, o Windows 7 apresenta o agendamento no modo de usuário :

O agendamento no modo de usuário (UMS) é um mecanismo leve que os aplicativos podem usar para agendar seus próprios threads. Um aplicativo pode alternar entre os threads do UMS no modo de usuário sem envolver o agendador do sistema e recuperar o controle do processador se um thread do UMS bloquear no kernel. Os segmentos UMS diferem das fibras, pois cada segmento UMS possui seu próprio contexto de segmento, em vez de compartilhar o contexto de segmento de um único segmento. A capacidade de alternar entre threads no modo de usuário torna o UMS mais eficiente que os pools de threads para gerenciar um grande número de itens de trabalho de curta duração que requerem poucas chamadas do sistema.

Mais informações sobre threads, fibras e UMS estão disponíveis no site Dave Probert: Inside Windows 7 - User Mode Scheduler (UMS) .

Grant Wagner
fonte
7

Os encadeamentos são agendados pelo sistema operacional (preventivo). Um encadeamento pode ser parado ou retomado a qualquer momento pelo sistema operacional, mas as fibras se gerenciam mais ou menos (cooperativas) e cedem uma à outra. Ou seja, o programador controla quando as fibras fazem seu processamento e quando esse processamento muda para outra fibra.

Arnold Spence
fonte
7

Os encadeamentos geralmente dependem do kernel para interromper o encadeamento para que ele ou outro encadeamento possa ser executado (o que é mais conhecido como multitarefa preemptiva), enquanto as fibras usam multitarefa cooperativa, onde é a própria fibra que perde o tempo de execução para que outras fibras podem correr.

Alguns links úteis que explicam melhor do que eu provavelmente são:

Mike Lowen
fonte
7

Threads foram originalmente criados como processos leves. De maneira semelhante, as fibras são um fio leve, confiando (simplisticamente) nas próprias fibras para se programarem, cedendo controle.

Eu acho que o próximo passo serão os fios em que você deve enviar um sinal a cada vez que quiser que eles executem uma instrução (não muito diferente do meu filho de 5 anos :-). Antigamente (e mesmo agora em algumas plataformas incorporadas), todos os threads eram fibras, não havia preempção e você tinha que escrever seus threads para se comportar bem.

paxdiablo
fonte
3

A definição de fibra do Win32 é, de fato, a definição "Green Thread" estabelecida na Sun Microsystems. Não há necessidade de desperdiçar o termo fibra no encadeamento de algum tipo, ou seja, um encadeamento em execução no espaço do usuário sob o controle do código do usuário / biblioteca de encadeamentos.

Para esclarecer o argumento, observe os seguintes comentários:

  • Com o hyperthreading, a CPU multinúcleo pode aceitar vários threads e distribuí-los um em cada núcleo.
  • A CPU com pipeline superescalar aceita um encadeamento para execução e usa o ILP (Instruction Level Parallelism) para executar o encadeamento mais rapidamente. Podemos supor que um segmento seja quebrado em fibras paralelas, executando em tubulações paralelas.
  • A CPU SMT pode aceitar vários threads e quebrá-los em fibras de instrução para execução paralela em vários pipelines, usando pipelines com mais eficiência.

Devemos assumir que os processos são feitos de fios e que os fios devem ser feitos de fibras. Com essa lógica em mente, o uso de fibras para outros tipos de threads está errado.

billmic
fonte
Isto é interessante.
JSON