Linguagem de programação moderna com abstrações intuitivas de programação simultânea [fechado]

39

Estou interessado em aprender programação concorrente, com foco no nível de aplicativo / usuário (não em programação do sistema). Eu estou procurando uma linguagem de programação moderna de alto nível que fornece abstrações intuitivas para escrever aplicativos simultâneos. Eu quero me concentrar em linguagens que aumentam a produtividade e escondem a complexidade da programação simultânea.

Para dar alguns exemplos, não considero uma boa opção escrever código multithread em C, C ++ ou Java porque IMHO minha produtividade é reduzida e seu modelo de programação não é intuitivo. Por outro lado, linguagens que aumentam a produtividade e oferecem abstrações mais intuitivas, como Python e o módulo de multiprocessamento, Erlang, Clojure, Scala, etc., seriam boas opções.

O que você recomendaria com base em sua experiência e por quê?

EDIT: Obrigado a todos por suas respostas interessantes. É difícil chegar a uma conclusão sem realmente tentar, pois há muitos bons candidatos: Erlang, Clojure, Scala, Groovy e talvez Haskell. Eu votei a resposta com os argumentos mais convincentes, mas vou tentar todos os bons candidatos antes de decidir qual escolher:)

    
por faif 12.03.2012 / 14:08
fonte

16 respostas

32

Você quase certamente deve olhar para o Clojure - na minha opinião, é a melhor linguagem moderna para programação multi-core e é extremamente produtiva.

Atributos principais:

  • É uma linguagem funcional , que é um benefício para a simultaneidade e sua capacidade de desenvolver usando abstrações de nível superior. Ele apresenta estruturas de dados persistentes totalmente imutáveis e sequências lentas que serão familiares para qualquer pessoa com experiência em linguagens funcionais como o Haskell.
  • Ele possui um sistema de memória transacional de software muito novo para acesso sem bloqueio simultâneo a um estado mutável. Tornar o código seguro para simultaneidade é geralmente tão simples quanto envolvê-lo em um bloco (dosync ....).
  • É um Lisp - o que o torna extremamente poderoso para metaprogramação baseada em macro e geração de código. Isso pode trazer vantagens significativas de produtividade (ensaio de Paul Graham - "Beating The Averages")
  • É uma linguagem da JVM - portanto, você não apenas obtém acesso à grande variedade de bibliotecas e ferramentas no ecossistema Java, como também se beneficia do enorme esforço de engenharia dedicado à criação da JVM uma plataforma eficaz para aplicativos simultâneos do lado do servidor. Para fins práticos, isso dá uma enorme vantagem sobre os idiomas que não têm esse tipo de base para construir.
  • É dinâmico - que resulta em código muito conciso e muita produtividade. No entanto, observe que você pode usar dicas de tipo estático opcionais para desempenho, se necessário.
  • A linguagem é projetada em torno de abstrações , o que é um pouco difícil de explicar, mas o efeito líquido é que você obtém um conjunto de recursos relativamente ortogonais que podem ser combinados para resolver seus problemas. Um exemplo seria a abstração de seqüência, que permite escrever código que lida com todo tipo de objeto "sequencial" (que inclui tudo, desde listas, strings, matrizes Java, sequências lentas infinitas, linhas sendo lidas de um arquivo etc.) / li>
  • Existe uma ótima comunidade - útil, perspicaz, mas, o mais importante, muito pragmática - o foco no Clojure é geralmente "fazer as coisas acontecerem".

Algumas mini-amostras de código com uma inclinação simultânea:

;; define and launch a future to execute do-something in another thread
(def a (future (do-something)))

;; wait for the future to finish and print its return value
(println @a)

;; call two functions protected in a single STM transaction
(dosync
  (function-one)
  (function-two))

Em particular, vale a pena assistir a um ou mais desses vídeos:

por 29.12.2014 / 14:36
fonte
27

Você poderia tentar D. Ele oferece três modelos. Eu recomendo o primeiro ou o segundo.

  1. std.concurrency . Se você usar este módulo para todas as suas necessidades de simultaneidade, uma combinação do idioma e da biblioteca padrão reforçará o isolamento entre os threads. Os threads se comunicam principalmente por meio da transmissão de mensagens, com suporte limitado à memória compartilhada de uma maneira que favorece a "segurança em primeiro lugar" e não permite corridas de dados de baixo nível. Infelizmente, a documentação da concorrência precisa de melhorias, mas o modelo está documentado em um capítulo livre do livro de Andrei Alexandrescu, "A linguagem de programação D".

  2. std.parallelism . Este módulo é projetado especificamente para paralelismo multicore ao invés de simultaneidade de casos gerais. Concorrência e paralelismo não são a mesma coisa, embora a simultaneidade seja necessária para implementar o paralelismo. / a>) Como todo o ponto de paralelismo é o desempenho, o std.parallelism não oferece garantias de isolamento porque tornariam difícil escrever código paralelo eficiente. No entanto, abstrai muitos detalhes de baixo nível propensos a erros, de modo que é muito difícil errar se você estiver fazendo o paralelismo das cargas de trabalho verificadas manualmente e se forem mutuamente independentes.

  3. core.thread é um wrapper de baixo nível sobre encadeamento específico do sistema operacional APIs. Ambos std.concurrency e std.parallelism usam isto sob o capô, mas eu recomendaria apenas usá-lo se você está escrevendo sua própria biblioteca de concorrência ou encontrar algum caso de canto ridículo que não pode ser feito bem em std.parallelism ou std .concurrency. Ninguém deve usar algo de baixo nível para o trabalho do dia-a-dia.

por 03.06.2013 / 16:12
fonte
23

O Erlang é definitivamente uma ótima opção, mas algo um pouco mais prático pode ser Ir , o novo idioma do Google.

Não está tão longe de outras linguagens comuns, por isso normalmente é fácil de obter se você já conhece outras linguagens 'fáceis'. Muitas pessoas o comparam com o Python ou até com a Lua em termos de quão "confortável" é programar.

    
por 22.11.2011 / 19:56
fonte
23

Dê uma olhada em Programação Paralela da Microsoft para .net. É muito intuitivo.

Many personal computers and workstations have two or four cores (that is, CPUs) that enable multiple threads to be executed simultaneously. Computers in the near future are expected to have significantly more cores. To take advantage of the hardware of today and tomorrow, you can parallelize your code to distribute work across multiple processors. In the past, parallelization required low-level manipulation of threads and locks. Visual Studio 2010 and the .NET Framework 4 enhance support for parallel programming by providing a new runtime, new class library types, and new diagnostic tools. These features simplify parallel development so that you can write efficient, fine-grained, and scalable parallel code in a natural idiom without having to work directly with threads or the thread pool. The following illustration provides a high-level overview of the parallel programming architecture in the .NET Framework 4... http://i.msdn.microsoft.com/dynimg/IC292903.png

    
por 03.06.2013 / 14:15
fonte
20

Tanto o Erlang quanto o Scala têm concorrência baseada em atores , que eu achei muito intuitiva e fácil de aprender.

The Actor model in computer science is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent digital computation: in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and determine how to respond to the next message received... It has been used both as a framework for a theoretical understanding of computation, and as the theoretical basis for several practical implementations of concurrent systems.

    
por 03.06.2013 / 14:17
fonte
18

Estou aprendendo sobre Haskell agora, e lendo este artigo me convenceu de que Haskell é uma boa opção para programação concorrente. Como é puramente funcional (o sistema de tipos sabe se uma função faz alguma entrada, saída ou leitura / modificação do estado global), ela pode fazer coisas como Memória Transacional de Software (resumida muito bem no artigo acima) que se comporta de maneira semelhante às transações em bancos de dados - você recebe um monte de coisas legais como atomicidade com apenas um pouco de açúcar extra. Os fios AFAIK e Haskell também são muito leves. Além dessas coisas, o fato de o Haskell ser puramente funcional permite que até tarefas simples sejam executadas em paralelo com pouco mais que uma única palavra-chave (par). fonte

    
por 25.11.2011 / 09:26
fonte
7

A linguagem GO do Google tem algumas ferramentas interessantes para a simultaneidade - isso seria outra coisa divertida para experimentar. Veja: link e leia um pouco para ver exemplos.

Concurrent programming is a large topic and there is space only for some Go-specific highlights here.

Concurrent programming in many environments is made difficult by the subtleties required to implement correct access to shared variables. Go encourages a different approach in which shared values are passed around on channels and, in fact, never actively shared by separate threads of execution. Only one goroutine has access to the value at any given time. Data races cannot occur, by design. To encourage this way of thinking we have reduced it to a slogan:

Do not communicate by sharing memory; instead, share memory by communicating.

     

Essa abordagem pode ser levada longe demais. A contagem de referências pode ser melhor feita colocando um mutex em torno de uma variável inteira, por exemplo. Mas, como uma abordagem de alto nível, o uso de canais para controlar o acesso torna mais fácil escrever programas claros e corretos.

     

Uma maneira de pensar sobre esse modelo é considerar um típico programa de encadeamento único executado em uma CPU. Não há necessidade de primitivos de sincronização. Agora execute outra instância desse tipo; também não precisa de sincronização. Agora deixe esses dois se comunicarem; Se a comunicação for o sincronizador, ainda não há necessidade de outra sincronização. Pipelines Unix, por exemplo, se encaixam perfeitamente nesse modelo. Embora a abordagem de Go para a concorrência tenha origem nos Processos Seqüenciais de Comunicação (CSP) de Hoare, ela também pode ser vista como uma generalização segura de tipos de pipes Unix ...

    
por 03.06.2013 / 14:19
fonte
6

Eu ainda recomendo o C ++. É mais do que capaz de abstrações necessárias para escrever código concorrente decente. A grande probabilidade é que você simplesmente tenha uma biblioteca ruim para fazer o trabalho, já que as bibliotecas boas para fazer o trabalho são relativamente novas e, de fato, o conhecimento para usar C ++ não é exatamente comum. O TBB da Intel só existe há alguns anos, e o PPL da Microsoft só é comercializado desde o ano passado.

Se você usa algo como TBB ou PPL, então o código concorrente não é exatamente trivial para escrever, na medida em que a simultaneidade nunca é trivial, mas longe de ser árdua. Se você usa pthreads ou threads do Win32 diretamente, então não é de admirar que você não goste - você está praticamente escrevendo em assembler com essas funções. Mas com o PPL, você está falando sobre algoritmos funcionais padrão que são paralelizados para você, estruturas de dados genéricas para acesso simultâneo e esse tipo de coisa boa.

    
por 23.11.2011 / 09:05
fonte
6

Um plug para Ada é necessário aqui, já que tem todas as abstrações de nível superior para paralelismo & concorrência. também conhecido como tasking . Também, como OP pediu por intuitivo (um critério subjetivo!), Acho que uma abordagem diferente para o mundo centrado em java pode ser apreciada.

    
por 25.11.2011 / 11:21
fonte
5

Na próxima versão, o C # torna ainda mais fácil do que o diagrama mostra. Existem duas novas palavras-chave Async e Await.

O async é usado como um modificador de função e diz "esta operação realiza seu trabalho em outro thread.

Await é usado dentro de uma função Assíncrona, e é aqui que a mágica acontece. Basicamente Await diz ao compilador para executar a operação seguindo a palavra-chave em um thread separado e esperar pelos resultados. Qualquer código após a chamada de espera é executado após a operação.

ALÉM DISSO, a operação é sincronizada com o segmento de chamada (portanto, se você estiver executando uma operação de asynch em resposta a um clique no botão, não será necessário efetuar o postback manualmente no thread da interface do usuário). Duas pequenas palavras-chave e você obtém muito poder de simultaneidade. Leia mais aqui

    
por 22.11.2011 / 20:39
fonte
5

Eu sugeriria GPars / Java / GPars se você pode ser baseado em JVM, já que permite atores, fluxo de dados, comunicação de processos seqüenciais (CSP), paralelismo de dados, software de memória transacional (STM), agentes, ... O ponto aqui é que há muitos concorrentes de alto nível e modelos de paralelismo cada um dos quais tem diferentes "pontos doces". Você não quer usar um modelo que não esteja em harmonia com a solução para um problema que você está tentando construir. Idiomas e frameworks com apenas um modelo o coagem para o hacking de algoritmos.

É claro que posso ser visto como influenciado por ser colaborador do Groovy e do GPars. Por outro lado eu trabalho com CSP e Python, cf. Python-CSP.

Outro ponto é que a questão original é sobre a aprendizagem, não sobre como escrever um sistema de produção. Portanto, a combinação Groovy / Java / GPars é uma boa maneira de aprender, mesmo que o trabalho de produção final seja feito em C ++ usando algo como Just :: Thread Pro ou TBB em vez de ser baseado em JVM.

(Alguns links de URL perfeitamente razoáveis tiveram que ser removidos por causa de algum pânico sobre o spam do site host.)

    
por 23.11.2011 / 18:18
fonte
4

E quanto ao Clojure? Você pode usar o Swing, por exemplo, mas aproveitando o recurso de programação simultânea do Clojure? O Clojure tem uma boa integração com Java.

Além disso, você considerou o framework Java 7 Fork / Join ?

    
por 22.11.2011 / 22:31
fonte
2

Você também pode querer olhar Groovy e o GPars biblioteca. O GPars BTW é um pouco semelhante ao .NET Parallel Extension mencionado em outra resposta, mas a sintaxe flexível do Groovys faz com que ele seja lido melhor em algumas circunstâncias.

    
por 22.11.2011 / 20:53
fonte
0

Scala foi mencionada várias vezes nas perguntas e nas respostas, mas não vi nenhuma referência a Akka que é uma implementação do ator que pode ser usado com Scala e Java.

    
por 21.04.2012 / 23:51
fonte
-1

Eu acho que depende do que você está construindo. Aplicativos de desktop ou servidor? Ouvi isso (mas não tenho experiência pessoal) node.js excelente para programação simultânea de servidores (tanto em termos de código de escrita quanto em desempenho). Se eu quisesse escrever um novo aplicativo de servidor, provavelmente tentaria isso. Não tenho certeza sobre aplicativos de desktop ... Eu escrevi uma boa quantidade de coisas em C # e existem algumas ferramentas que escondem a complexidade muito bem, embora em outros casos você tenha que lidar com isso de frente.

    
por 22.11.2011 / 19:42
fonte
-1

Eu posso ser atingido na cabeça por isso, mas você leu o capítulo 7 do TAOUP ? A seção que estou pensando especificamente é threads vs processos. Descobri que o conceito de processamento simultâneo faz com que a maioria das pessoas pense em threads, mas nunca vi uma instância em que um thread seja mais fácil e rápido de usar do que gerar um processo filho.

Você está cultivando todos os detalhes de como lidar com a concorrência para os caras espertos que criaram seu sistema operacional. Já existem muitos métodos de comunicação, e você não precisa se preocupar com o bloqueio de recursos compartilhados. Basicamente, os threads são um hack de eficiência, que se enquadra na regra da otimização. Não otimize se você não tiver testado por necessidade.

Encontre uma boa biblioteca de subprocessos, como o envoy for python . Ou você poderia simplesmente escrever vários programas separados em C, e escrever outro programa "mestre" para usar o fork and pipe para gerar e se comunicar com os subprocessos.

    
por 12.03.2012 / 15:07
fonte