[RUBY] Coopération Rubis / Rouille (2) Moyens

Série d'articles

introduction

Il existe différents niveaux et méthodes pour lier Ruby et Rust.

Utiliser les commandes Rust

L'une des méthodes de coopération consiste à appeler l'outil CLI (en bref, la commande) créé par Rust de Ruby et à l'utiliser, bien que l'on puisse dire "Qu'est-ce qui ne va pas?"

Du côté Ruby, Kernel. # System et [IO.popen](https: // docs) Appelez un programme externe en utilisant .ruby-lang.org / ja / 2.7.0 / method / IO / s / popen.html).

Par exemple, supposons que vous ayez un fichier CSV avec un grand nombre de colonnes et de lignes et que vous souhaitiez en extraire certaines colonnes et effectuer un traitement tel que l'agrégation. Un outil appelé xsv créé par Rust est utile pour extraire des colonnes.

xsv select name,phone people.csv

Si vous écrivez, le CSV qui extrait uniquement la colonne de nom et la colonne de téléphone de people.csv sera envoyé à la sortie standard. C'est le prétraitement.

Cependant, peu importe qu'il s'agisse de Rust ou non si vous l'appelez simplement en tant que commande externe. Dans cette section, j'ai voulu montrer qu '"il existe un moyen de combiner un programme créé de manière totalement indépendante par appel de commande et entrée / sortie standard, même si cela s'appelle coopération", mais je ne le reviendrai pas plus tard.

FFI: via l'interface de fonction étrangère

(Remarque: comme pour les autres sections, je l'ai écrit sans le comprendre, il peut donc y avoir des erreurs)

FFI est appelé "autre interface de fonction de langage" en japonais, et est l'un des mécanismes pour appeler des fonctions (etc.) entre différents langages de programmation.

Le type de données qui peuvent être transmises semble être basé sur celui du langage C (?), Et il y a des restrictions considérables. Par exemple, même lors de l'échange d'entiers, il est nécessaire de clarifier le type tel que ʻuint8 (entier 8 bits non signé) et ʻint32 (entier 32 bits signé), et les objets Integer qui ne rentrent pas dans cette plage doivent être clarifiés. Vous ne pouvez pas le remettre. Il semble que même les tableaux et les hachages Ruby ne peuvent pas être échangés (du moins facilement). L'échange de chaînes de caractères est un peu gênant.

Je pense que c'est probablement la liste des types disponibles: Types · ffi/ffi Wiki

L'appel des fonctions Rust depuis Ruby via FFI n'est pas difficile. Du côté de la rouille

#[no_mangle]
pub extern fn hoge(x: f64, y: f64) -> f64 {
  x + y
}

Définissez et compilez la fonction comme suit.

Du côté Ruby, nous utilisons une gemme appelée ffi. Et

require "ffi"

module Hoge
  extend FFI::Library
  ffi_lib "path/to/library/file"
  attach_function :hoge, [:double, :double], :double
end

p Hoge.hoge(2.0, 3.0) # => 5.0

Appelez ça comme ça. N'est-il pas assez facile de battre le rythme?

Plus tard, j'écrirai un article dans FFI qui appelle les fonctions Rust de Ruby.

Helix

Alors que FFI est une spécification à usage général qui relie différents langages, Helix dans cette section et Rutie dans la section suivante ne servent qu'à connecter Ruby et Rust.

Vous pouvez voir les deux suivants sur le site officiel d'Helix.

De plus, les articles suivants sont très utiles.

Résumé de quelques façons d'appeler Rust depuis Ruby-Qiita

Dans l'exemple du site officiel, il est soudainement intégré au projet Ruby on Rails, et ce n'est pas clair pour ceux qui ne font pas de Rails, mais le site ci-dessus est un exemple de création d'un bijou et il est facile à comprendre.

Helix est incroyable que vous puissiez créer des classes Ruby avec Rust. Es-tu sérieux.

Du côté de la rouille, une caisse appelée hélice est utilisée. Ensuite, vous pouvez utiliser la macro ruby!

ruby! {
  class Hoge {
    //Méthode d'instance
    def foo(&self, s: String) {
    
    }
    
    //Méthode de classe
    def bar(s: String) {
    
    }
  }
}

Il semble que vous puissiez écrire comme ça. Contrairement à FFI, l'échange de chaînes de caractères est aussi simple que ci-dessus.

Ce qui est intéressant, c'est que les valeurs "String object ou nil" et "Float object" ou "nil" de Ruby peuvent être échangées comme ʻOption <String> et ʻOption ` de Rust (je ne sais pas). ).

Les tableaux et les hachages ne peuvent pas être échangés. Selon Roadmap, objectifs à long terme

Est en place.

Un peu décevant, c'est que le développement semble lent (à l'oeil). Au 4 septembre 2020

Il est devenu. Aussi, il est difficile de dire que la maintenance du site est suffisante.

Je n'ai pas encore essayé Helix, mais j'aimerais faire un peu plus de recherche et écrire un article.

Rutie

Rutie semble se prononcer comme "rooty". Cela semble être un nom d'implication tel que tie (tie) Ru of Ruby et Ru of Rust. Site officiel ici:

Comme Helix, Rust peut créer des classes Ruby. Vous pouvez également créer des modules. Du côté de la rouille, une caisse appelée rutie est utilisée. Par exemple

module!(Hoge);

mehtods!(
    Hoge,
    _rtself,
    
    fn foo(s: RString) -> RString {
        //Etc
    }
);

Il semble que vous puissiez définir le module Hoge et sa méthode singulière foo. (Un peu plus de description est nécessaire du côté Rust pour le rendre disponible en Ruby)

Côté Ruby, nous utilisons une gemme appelée rutie (même nom que la caisse). L'exemple de code du côté Ruby est omis. J'ai l'intention d'écrire un autre article plus tard.

Dans Rutie, vous pouvez également utiliser les méthodes Ruby du côté Rust. C'est intéressant. Cependant, je ne l'ai pas encore essayé, donc je ne suis pas sûr de ce que c'est.

La dernière version de Rutie en date du 4 septembre 2020 est juillet 2020 (version 0.8.0).

Autre

Il existe divers autres moyens.

Déjà mentionné

Résumé de quelques façons d'appeler Rust depuis Ruby-Qiita

Décrit également la méthode utilisant WASM (WebAssembly).

À propos, il y avait de nombreuses restrictions sur les types de données pouvant être échangées, qu'il s'agisse de FFI, Helix ou Rutie.

La méthode via Apache Arrow est-elle également prometteuse pour échanger d'énormes données? L'auteur n'en a aucune idée. Cependant, Ruby et Rust ont des bibliothèques qui utilisent Arrow.

Pour les applications avec des structures compliquées qui ne se soucient pas du temps d'encodage / décodage, il peut être possible d'utiliser JSON ou MessagePack. JSON et MessagePack sont faciles à utiliser avec Ruby et Rust.

Test de référence (ajouté le 18/09/2020)

Je n'ai pas comparé moi-même la vitesse de chaque méthode, mais j'ai trouvé un site de test de référence. https://github.com/bbugh/ruby-rust-extension-benchmark (Octobre 2019)

Helix semble être plus lent que Rutie dans ce test de référence. Le coût de l'interaction entre Ruby / Rust peut être un peu élevé.

Les tests de référence modifient souvent leur classement avec seulement des changements mineurs de contenu et d'échelle, et il peut être dangereux de prendre une décision basée uniquement sur les tests ci-dessus. Cependant, en regardant la fonctionnalité et le rythme du développement, je pense que Rutie est celui du moment si un seul d'entre eux est étudié et utilisé.

Recommended Posts

Coopération Rubis / Rouille (2) Moyens
Coopération rubis / rouille (1) Objectif
Coopération rubis / rouille (6) Extraction de morphologie
Liaison Ruby / Rust (4) Calcul numérique avec Rutie