Vale a pena mudar de Python para Nim para desempenho?

Nim é uma mistura de sintaxe Python e desempenho C







Algumas semanas atrás, eu estava navegando no GitHub e me deparei com um repositório curioso: o projeto foi escrito inteiramente em Nim . Eu não o tinha visto antes, e desta vez decidi descobrir que tipo de animal era.



A princípio pensei que estava atrasado, que esta é uma das linguagens de programação mais difundidas que muitos, ao contrário de mim, usam ativamente. E então decidi estudá-lo.



Aqui estão minhas conclusões:



  • Esta linguagem é realmente popular entre um círculo restrito de pessoas.
  • Talvez devesse ser assim.


Então, vou contar um pouco sobre minha experiência com o Nim, falar brevemente sobre os recursos de programação nele e também tentar compará-lo com Python e C. Olhando para o futuro, observo que essa linguagem parece muito promissora para mim.



Código no estúdio!



Por exemplo, decidi escrever algo mais complexo em Nim do que hello, world:







Parece nada supérfluo, certo? Parece tão simples que você pode facilmente descobrir o que ele faz, mesmo que você nunca tenha ouvido falar de Nim antes. (O programa produzirá: "num: 5 i: 5")



Então, vamos analisar o que parece familiar para nós de algum lugar.



Declaração de variável



Isso é dolorosamente familiar para os desenvolvedores de JavaScript. Enquanto algumas linguagens usam var e outras usam let, JS e Nim permitem que você use ambos ao declarar variáveis. No entanto, é importante observar que eles funcionam de maneira diferente no Nim e no JS. Mas mais sobre isso mais tarde.



Blocos



Para denotar um novo bloco em Nim, usamos dois pontos seguidos por uma linha recuada. Tudo é como em Python.



Palavras-chave



Ambos os loops e a instrução if parecem ser uma parte do código Python. Na verdade, tudo da linha 5 em diante é código Python (assumindo que temos a função echo definida).



Então, sim, muitas palavras-chave e operadores Python também podem ser usados ​​no Nim: não, é, e, ou e assim por diante.



Ou seja, até agora não vimos nada de especial no Nim: a pior versão do Python (em termos de

sintaxe), levando em consideração o fato de que você precisa usar let ou var para declarar variáveis.



Poderíamos parar por aí, mas há um grande "mas": Nim é uma linguagem de tipagem estática que funciona quase tão rápido quanto a linguagem C.



Bem, agora para outra conversa. Vamos dar uma olhada.



Teste de performance







Antes de mergulharmos na sintaxe do Nim (especialmente a parte com tipo estático que não vimos até agora), vamos tentar avaliar seu desempenho. Para fazer isso, escrevi uma implementação ingênua para calcular o enésimo número de Fibonacci em Nim, Python e C.



Para manter as coisas justas, padronizei a implementação com base na solução Leetcode (Opção 1) e tentei segui-la o mais estritamente possível nas três linguagens.



Você pode, é claro, me lembrar do LRU Cache . Mas, por enquanto, minha tarefa é usar uma abordagem padrão e não tentar otimizar cálculos. Então, escolhi uma implementação ingênua.


Aqui estão os resultados para calcular o 40º número de Fibonacci:







Sim, estritamente falando, o experimento não pode ser chamado de puro, mas isso se correlaciona com os resultados de outros entusiastas que fizeram testes mais sérios [1] [2] [3] .



Todo o código que escrevi para este artigo está disponível no GitHub, incluindo instruções sobre como executar esse experimento.



Então, por que o Nim é muito mais rápido do que o Python?



Bem, eu diria que há duas razões principais:



  1. Nim é uma linguagem compilada e Python é uma linguagem interpretada (mais sobre isso aqui ). Isso significa que mais trabalho é feito quando um programa Python é executado porque o programa deve ser interpretado antes de poder ser executado. Isso geralmente torna o idioma mais lento.
  2. Nim é digitado estaticamente. Embora não tenha havido declaração de tipo no exemplo que mostrei anteriormente, veremos mais tarde que é realmente uma linguagem com tipagem estática. No caso do Python, que é digitado dinamicamente, há muito mais trabalho a ser feito pelo interpretador para definir e manipular os tipos de maneira apropriada. Também reduz o desempenho.


A velocidade de trabalho aumenta - a velocidade de codificação diminui



Aqui está o que o Python Docs diz sobre linguagens interpretadas:

« / , , ».


Esta é uma boa generalização da troca entre Python e C, por exemplo. Tudo que você pode fazer em Python, você pode fazer em C, mas seu programa em C será executado muito mais rápido.



Mas você vai gastar muito mais tempo escrevendo e depurando seu código C, ele será pesado e menos legível. E é por isso que C não é mais procurado e Python é popular. Em outras palavras, Python é muito mais simples (comparativamente, é claro).



Portanto, se Python está em uma extremidade do espectro e C está na outra, então Nim está tentando chegar a algum lugar no meio. É muito mais rápido que Python, mas não tão difícil de programar quanto C.



Vamos dar uma olhada em nossa implementação de cálculo de números de Fibonacci.



A PARTIR DE:



#include <stdio.h>
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    } 
    return fibonacci(n-1) + fibonacci(n-2);
}

int main(void) {
    printf("%i", fibonacci(40));
}


Pitão:



def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(40))


Nim:



proc fibonacci(n: int): int = 
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

echo(fibonacci(40))


Embora o Nim use o sinal "=" em sua sintaxe de procedimento (função), em geral é muito mais fácil escrever código do que em C.



Talvez esta seja realmente uma compensação válida? Um pouco mais difícil de escrever do que Python, mas funciona dez vezes mais rápido. Eu poderia viver com isso.



Sintaxe Nim



import strformat

#    https://nim-lang.org/

type
  Person = object
    name: string
    age: Natural #      

let people = [
  Person(name: "John", age: 45),
  Person(name: "Kate", age: 30)
]

for person in people:

  echo(fmt"{person.name} is {person.age} years old")


Vou apenas apontar os principais recursos.



Variáveis



Usamos var, let ou const para declarar variáveis.



var e const funcionam da mesma maneira que em JavaScript, mas vamos ver uma história diferente.



JavaScript let difere de var em termos de escopo, e Nim let denota uma variável cujo valor não pode ser alterado após a inicialização. Parece Swift para mim.



Mas isso não é o mesmo que uma constante? - você pergunta.



Não. Em Nim, a diferença entre const e let é a seguinte:

Para const, o compilador deve ser capaz de determinar o valor em tempo de compilação, enquanto para let pode ser determinado em tempo de execução.


Exemplo da documentação:



const input = readLine(stdin) # Error: constant expression expected
let input = readLine(stdin)   #  


Como alternativa, as variáveis ​​podem ser declaradas e inicializadas assim:



var
   a = 1
   b = 2
   c = 3
   x, y = 10 #   x  y   10


Funções



As funções no Nim são chamadas de procedimentos:



proc procedureName(parameterName: parameterType):returnType =
   return returnVar


Dado que a linguagem é semelhante ao Python em muitos aspectos, os procedimentos parecem um pouco estranhos quando você os vê pela primeira vez.



Usar "=" em vez de "{" ou ":" é claramente confuso. Tudo fica um pouco melhor escrevendo o procedimento em uma linha:



proc hello(s: string) = echo s


Você também pode obter o resultado da função:



proc toString(x: int): string =
   result =
       if x < 0: “negative”
       elif x > 0: “positive”
       else: “zero”


Parece que você ainda precisa retornar o resultado de alguma forma, mas, neste caso, o resultado não é uma variável - é uma palavra-chave. Portanto, o trecho de código acima estará correto do ponto de vista de Nim.



Você também pode sobrecarregar os procedimentos:




proc toString(x: int): string =   
    result =     
        if x < 0: "negative"     
        elif x > 0: "positive"     
        else: "zero"  
proc toString(x: bool): string =   
    result =     
        if x: "yep"     
        else: "nope"
echo toString(true) #  "yep"
echo toString(5) #  "positive"


Condições e ciclos



Tem muito a ver com Python.



# if true:

# while true:

# for num in nums:


Para iterar em uma lista, por exemplo, em vez de range (), você pode usar a contagem (início, término) ou contagem regressiva (início, término) . Você pode fazer isso ainda mais fácil e usar for i in start..finish



Entrada e saída do usuário



let input = readLine(stdin)
echo input


Comparado ao Python, readLine (stdin) é equivalente a input () e echo é equivalente a print.



echo pode ser usado com ou sem parênteses.



Meu objetivo é dar a você uma compreensão básica do Nim, não recontar toda a sua documentação. Então, acabo com a sintaxe e passo para outros recursos da linguagem.



Recursos extras



Programação Orientada a Objetos



Nim não é uma linguagem orientada a objetos, mas fornece suporte mínimo para trabalhar com objetos . Claro, ele está longe das classes Python.



Macros



O Nim oferece suporte a macros e metaprogramação, e os desenvolvedores parecem estar colocando muita ênfase nisso. Este é o assunto de sua própria seção da série de três lições.



Pequeno exemplo:



import macros  macro myMacro(arg: static[int]): untyped =  
   echo arg

myMacro(1 + 2 * 3)


Tipos de dados básicos



string, char, bool, int, uint  float.


Você também pode usar estes tipos:



int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64


Além disso, as strings no Nim são tipos mutáveis, ao contrário do Python.



Comentários



Ao contrário do Python, o Nim usa o caractere "#" em combinação com "[" e "]" para comentários de várias linhas.



# a comment#[
a
multi
line
comment
]#


Compilando JavaScript



Nim pode traduzir seu código para JavaScript. Não tenho certeza se muitas pessoas vêm para usar isso. Mas há um exemplo de jogo de navegador de cobra escrito em Nim.



Iteradores



Os iteradores Nim são mais parecidos com geradores Python:



iterator countup(a, b: int): int =
   var res = a
   while res <= b:
       yield res
       inc(res)


Sensibilidade a maiúsculas e minúsculas e sublinhado

Nim é sensível a maiúsculas e minúsculas apenas para o primeiro caractere.



Ou seja, ele distingue HelloWorld e helloWorld, mas não helloWorld, helloworld e hello_world. Portanto, o seguinte procedimento funcionará sem problemas, por exemplo:



proc my_func(s: string) =
   echo myFunc("hello")


Quão popular é Nim?







Nim tem quase 10.000 estrelas no GitHub. Esta é uma clara vantagem. Mesmo assim, tentei estimar a popularidade da língua a partir de outras fontes e, claro, não é tão alta.



Por exemplo, Nim nem mesmo foi mencionado na Pesquisa Stack Overflow de 2020 . Não consegui encontrar empregos de desenvolvedor Nim no LinkedIn (mesmo com a geografia mundial) e uma pesquisa pela tag [nim-lang] no Stack Overflow retornou apenas 349 perguntas (compare com ~ 1.500.000 para Python ou 270.000 para Swift)



. Portanto, seria justo presumir que a maioria dos desenvolvedores não o usou e muitos nunca ouviram falar da linguagem Nim.



Substituindo Python?



Para ser honesto, acho que Nim é uma linguagem muito legal. Para escrever este artigo, estudei o mínimo exigido, mas foi o suficiente. Embora não tenha me aprofundado muito nisso, planejo usar o Nim no futuro. Pessoalmente, sou um grande fã de Python, mas também gosto de linguagens com tipos estáticos. Então, para mim, a melhoria de desempenho em alguns casos mais do que compensa um pouco de redundância sintática.



Embora a sintaxe básica seja muito semelhante à do Python, é mais complexa. Portanto, a maioria dos fãs de Python provavelmente não se interessará por ele.



Além disso, não se esqueça da linguagem Go. Tenho certeza de que muitos de vocês pensaram nisso exatamente como leram, e com razão. Apesar de a sintaxe do Nim ser mais próxima da sintaxe do Python, em termos de desempenho ela compete justamente com linguagens como "C ++ simplificado".

Uma vez testei o desempenho do Go. Em particular, para Fibonacci (40), funcionou tão rápido quanto C.


Mesmo assim: o Nim pode competir com o Python? Eu duvido muito. Estamos vendo uma tendência de aumento do desempenho do computador e simplificação da programação. E, como observei, mesmo que o Nim ofereça uma boa relação entre sintaxe e desempenho, não acho que seja o suficiente para vencer o Python puro e versátil.

Falei com um dos desenvolvedores do Nim Core. Ele acha que o Nim é mais adequado para quem está migrando do C ++ do que para pythonistas.


O Nim pode competir com o Go? Possivelmente (se o Google "permitir"). A linguagem Nim é tão poderosa quanto Go. Além disso, o Nim tem melhor suporte para recursos C / C ++, incluindo macros e sobrecarga.



Mas mais sobre isso na próxima vez.






Publicidade



Os servidores Epic são servidores virtuais acessíveis com processadores AMD, frequência de núcleo de CPU de até 3,4 GHz. A configuração máxima permitirá que você chegue ao máximo - 128 núcleos de CPU, 512 GB de RAM, 4000 GB NVMe. Apresse-se para fazer o pedido!






All Articles