Um padrão que me deparei várias vezes agora é aquele em que uma lista de valores precisa ser verificada mapeando algum teste sobre ele e verificando se algum ou todos os elementos foram aprovados. A solução típica é apenas usar os convenientes embutidos all
e any
.
O problema é que eles são avaliados em série. Em muitos casos, seria muito mais rápido avaliar em paralelo com o processo sendo concluído quando qualquer encadeamento encontrar um "False" para all
ou um "True" para any
. Tenho certeza de que o comportamento em curto-circuito não pode ser implementado usando Control.Parallel, pois requer comunicação entre processos e não entendo em lugar algum o Control.Concurrent para implementar isso ainda.
É um padrão bastante comum em matemática (por exemplo, Miller-Rabin Primality), então eu sinto que alguém provavelmente já encontrou uma solução para isso, mas por razões óbvias fazendo uma pesquisa no google por "paralelo ou / e / qualquer / tudo na lista" haskell "não retorna muitos resultados relevantes.
fonte
unamb
bibliotecapthreads
em C ou em verde em Haskell). Você inicia vários servidores da web para lidar com solicitações simultâneas da web, em vez de executar vários threads em um único processo! O mesmo se aplica ao paralelismo. Você gira o número de threads que possui CPUs e divide seu trabalho uniformemente, cuidando das tarefas ligadas à CPU. Tente esta biblioteca para se convencer github.com/lehins/haskell-schedulerRespostas:
Em muitos programas realistas, você pode usar estratégias paralelas para esse fim. Isso ocorre porque, embora não exista um mecanismo explícito para cancelar cálculos desnecessários, isso acontecerá implicitamente quando o coletor de lixo for executado. Como um exemplo concreto, considere o seguinte programa:
Isso usa uma estratégia de lista paralela para procurar
waldo = 0
(que nunca será encontrada) na saída de 100 fluxos PRNG de 40 milhões de números cada. Compile e execute:e prende quatro núcleos por cerca de 16s, eventualmente imprimindo
False
. Observe nas estatísticas que todas as 100 faíscas são "convertidas" e, portanto, executadas até a conclusão:Agora, mude
waldo
para um valor que pode ser encontrado mais cedo:e modifique
main
para manter o encadeamento ativo por 10 segundos:Você observará que a impressora é impressa
True
quase imediatamente, mas quatro núcleos permanecem fixados em 100% da CPU (pelo menos por um tempo), ilustrando que os cálculos desnecessários continuam em execução e não estão em curto-circuito, como você poderia temer.MAS , as coisas mudam se você forçar uma coleta de lixo após obter a resposta:
Agora, você verá que a CPU fica ociosa logo após a impressão
True
e as estatísticas mostram que a maioria dos cálculos foram coletados como lixo antes da execução:Em programas realistas, um explícito
performGC
não será necessário, pois os GCs serão realizados regularmente como uma questão de curso. Alguns cálculos desnecessários continuarão em execução após a resposta ser encontrada, mas em muitos cenários realistas, a fração de cálculos desnecessários não será um fator particularmente importante.Em particular, se a lista for grande e cada teste individual de um elemento da lista for rápido, as estratégias paralelas terão excelente desempenho no mundo real e serão fáceis de implementar na barganha.
fonte