O outro lado do Ruby

O outro lado do Ruby

Depois de explorarmos as características, recursos e vantagens do Ruby, é hora de discutir um pouco sobre seus pontos negativos!

Desempenho:

Comparado a linguagens de baixo nível como C++ ou Go, o Ruby pode ser mais lento em termos de velocidade de execução bruta. Isso pode ser uma preocupação para aplicativos que exigem alta performance.

Podemos utilizar a gem benchmark para medir o desempenho de diferentes partes do seu código em Ruby. Aqui está um exemplo simples de como você pode usar o benchmark para medir o tempo de execução de uma função:

    
      require 'benchmark'

      # Defina a função que você deseja testar
      def minha_funcao
        resultado = 0
        1000000.times do
          resultado += 1
        end
        return resultado
      end

      # Use o método benchmark para medir o tempo de execução da função
      tempo = Benchmark.realtime do
        minha_funcao
      end

      puts "Tempo de execução: #{tempo.round(4)} segundos"

    
  

Definimos uma função simples chamada minha_funcao que simplesmente soma 1 ao resultado um milhão de vezes.

Usamos o Benchmark.realtime para medir o tempo de execução da função. Imprimimos o tempo de execução resultante.

Simultaneidade e Paralelismo:

A implementação padrão do Ruby (MRI - Matz's Ruby Interpreter) tem limitações no tratamento de simultaneidade e paralelismo. Embora existam alternativas como JRuby e Rubinius que melhoram nessa área, ainda não são tão eficazes quanto linguagens projetadas com a simultaneidade em mente.

Simultaneidade: Refere-se à execução concorrente de várias tarefas em um único núcleo de CPU. Em Ruby, você pode usar threads para criar tarefas simultâneas.

Paralelismo:Refere-se à execução de várias tarefas ao mesmo tempo em diferentes núcleos de CPU. Em Ruby, isso é limitado devido ao GIL (Global Interpreter Lock), mas você ainda pode alcançar algum paralelismo em operações de E/S intensivas, como solicitações de rede

	
    # Importa a biblioteca necessária
    require 'net/http'

    # Define uma lista de URLs para fazer solicitações simultâneas
    urls = ['https://www.example.com', 'https://www.google.com', 'https://www.github.com']

    # Define uma função para fazer uma solicitação HTTP e imprimir o status da resposta
    def fazer_solicitacao(url)
      uri = URI(url)
      response = Net::HTTP.get_response(uri)
      puts "URL: #{url}, Status: #{response.code}"
    end

    # Cria uma thread para cada URL na lista
    threads = urls.map do |url|
      Thread.new { fazer_solicitacao(url) }
    end

    # Aguarda todas as threads terminarem
    threads.each(&:join)
    

Importamos a biblioteca net/http para fazer solicitações HTTP.

Definimos uma lista de URLs para fazer solicitações simultâneas.

Criamos uma função fazer_solicitacao que faz uma solicitação HTTP para uma URL e imprime o status da resposta.

Para cada URL na lista, criamos uma nova thread que chama a função fazer_solicitacao com essa URL.>Aguardamos todas as threads terminarem usando o método join.

Isso demonstra simultaneidade, pois várias solicitações HTTP são feitas simultaneamente em threads separadas, permitindo que o programa execute várias tarefas ao mesmo tempo em um único núcleo de CPU.

Uso de Memória:

O Ruby pode consumir muita memória, o que pode não ser ideal para projetos com restrições de memória ou aplicativos de grande escala.

Para analisarmos o consumo de memoria com ruby, podemos utilizar o exemplo abaixo, onde conseguimos ver a quantidade de memoria usada.

  
    # Defina uma função para criar um grande array de strings
    def criar_array_grande
      array_grande = []
      1000000.times do |i|
        array_grande << "String #{i}"
      end
      return array_grande
    end

    # Chame a função para criar o array grande
    array = criar_array_grande

    # Imprima a quantidade de memória usada pelo programa
    puts "Memória utilizada pelo programa: #{`ps -o rss= -p #{Process.pid}`.to_i} KB"
  
 

A função criar_array_grande cria um grande array de strings, contendo um milhão de elementos, onde cada elemento é uma string contendo o texto "String" seguido pelo número do índice.

Depois que o array é criado, usamos a sintaxe `` para executar um comando do sistema operacional que nos dá a quantidade de memória usada pelo processo Ruby.

Finalmente, imprimimos a quantidade de memória usada pelo programa.

Agora se compararmos com o go, utilizando a mesma logica, porem com o script abaixo:

  	
      package main

      import (
          "fmt"
          "os"
          "runtime"
      )

      // Função para criar uma grande fatia de strings
      func criarSliceGrande() []string {
          var sliceGrande []string
          for i := 0; i < 1000000; i++ {
              sliceGrande = append(sliceGrande, fmt.Sprintf("String %d", i))
          }
          return sliceGrande
      }

      func main() {

          // Obtém estatísticas de memória
          var m runtime.MemStats
          runtime.ReadMemStats(&m)

          // Imprime a quantidade de memória usada pelo programa
          fmt.Printf("Memória utilizada pelo programa: %d KB\n", m.Alloc/1024)

          // Força uma pausa para permitir que você veja o uso de memória antes de sair
          fmt.Println("Pressione Enter para sair...")
          fmt.Scanln()

          // Garante que o programa termine com um status de saída zero
          os.Exit(0)
      }
  	
  

Bloqueio Global de Intérprete (GIL):

O GIL no MRI pode limitar a utilização total de processadores multi-core, afetando o desempenho em aplicações fortemente simultâneas.

Curva de Aprendizado para Aplicações Complexas:

Embora o Ruby seja conhecido por sua sintaxe elegante, aplicativos complexos podem exigir um profundo conhecimento dos recursos e padrões de design avançados, o que pode resultar em uma curva de aprendizado mais íngreme.

Disponibilidade de Bibliotecas e Ferramentas:

Embora o ecossistema do Ruby seja robusto, pode não ser tão abrangente quanto o de outras linguagens, especialmente em nichos ou domínios especializados.

Suporte Limitado ao Desenvolvimento Móvel:

O Ruby não é amplamente utilizado para o desenvolvimento de aplicativos móveis, o que pode exigir a busca por outras linguagens ou frameworks para esses projetos.

Implantação e Hospedagem:

A configuração de um ambiente Ruby pode ser mais complexa em comparação com linguagens com procedimentos de implantação mais padronizados.

Comunidade e Suporte:

Embora tenha uma comunidade ativa, ela pode não ser tão grande quanto as de outras linguagens, afetando a disponibilidade de recursos e suporte.

Menos Popularidade em Alguns Domínios:

Em certos domínios especializados, Ruby pode não ser a primeira escolha devido à falta de bibliotecas ou ferramentas especializadas.

Comentários

Postagens mais visitadas deste blog

Entendendo Estruturas de Dados: O Que São e Por Que São Importantes?

Entendendo a Notação Big O em Go