発音 R-アクトール
純粋な Rust アクターフレームワーク。アーランのgen_server
にインスパイアされた、Rustのスピード+パフォーマンスで!
ractorRustでErlangのようなアクターフレームワークを構築および維持する問題を解決しようとします。それは与える ジェネリックプリミティブのセットであり、従来のアクターメッセージ処理ロジックとともにアクターの監視ツリーと管理を自動化するのに役立ちます。それは重く構築されています の厳しい要件。
tokio
ractor
ractorは、コードなしで100%錆びて書かれた最新のアクターフレームワークです。
unsafe
さらに、分散(クラスターのような)シナリオで展開するために必要なコンパニオンライブラリがあります。 まだ一般公開の準備ができていませんが、進行中の作業であり、まもなく登場します!
ractor
ractor_cluster
ractor
ractor_cluster
Rustで書かれた他のアクターフレームワーク(Actix、riker、またはTokioのアクターのみ)に加えて、このRedditの投稿にまとめられたリスト全体があります。
Ractorは、純粋なアーランをもっとモデル化することで、違うことを試みます。これは、各アクターが追加費用なしで他のアクターのスーパーバイザーになることができることを意味します(単にそれらをリンクするだけです!さらに、Erlangのパターンは非常にうまく機能し、業界でよく利用されているため、Erlangのパターンと緊密なロジックを維持することを目指しています。
gen_server
さらに、生成する必要のあるある種の「ランタイム」または「システム」に基づいて構築せずに書きました。アクタは、他の基本的なランタイムと組み合わせて独立して実行でき、オーバーヘッドはほとんど追加されません。
ractor
tokio
現在、以下を完全にサポートしています。
済みプロセス
からの名前付きアクターレジストリ()ractor::registry
pgモジュール
からのプロセスグループ()ractor::pg
ロードマップでは、分散アクタークラスターを含むErlang機能をさらに追加します。
のアクターは一般的に非常に軽量であり、独自のホストシステムで実行できるベンチマークがあります。
ractor
cargo bench -p ractor
Cargo.tomlの依存関係に以下を追加してインストールします。
ractor
[dependencies]
ractor = "0.7"
ractor現在、単一の機能、つまり次の機能を公開しています。
clusterこれは、ネットワーク リンクを介してアクターのクラスターを設定および管理するために必要なさまざまな機能を公開します。これは進行中の作業であり、#16で追跡されています。
ractor_cluster
のアクターは非常に軽量で、スレッドセーフとして扱うことができます。各アクターは、一度に1つのハンドラー関数のみを呼び出し、 並列で実行されることはありません。アクター モデルに従うと、明確に定義された状態と処理ロジックを持つマイクロサービスが実現します。
ractor
アクターの例は次のとおりです。
ping-pong
use ractor::{cast, Actor, ActorProcessingErr, ActorRef};
/// [PingPong] is a basic actor that will print
/// ping..pong.. repeatedly until some exit
/// condition is met (a counter hits 10). Then
/// it will exit
pub struct PingPong;
/// This is the types of message [PingPong] supports
#[derive(Debug, Clone)]
pub enum Message {
Ping,
Pong,
}
impl Message {
// retrieve the next message in the sequence
fn next(&self) -> Self {
match self {
Self::Ping => Self::Pong,
Self::Pong => Self::Ping,
}
}
// print out this message
fn print(&self) {
match self {
Self::Ping => print!("ping.."),
Self::Pong => print!("pong.."),
}
}
}
// the implementation of our actor's "logic"
#[async_trait::async_trait]
impl Actor for PingPong {
// An actor has a message type
type Msg = Message;
// and (optionally) internal state
type State = u8;
// Startup initialization args
type Arguments = ();
// Initially we need to create our state, and potentially
// start some internal processing (by posting a message for
// example)
async fn pre_start(
&self,
myself: ActorRef<Self>,
_: (),
) -> Result<Self::State, ActorProcessingErr> {
// startup the event processing
cast!(myself, Message::Ping)?;
// create the initial state
Ok(0u8)
}
// This is our main message handler
async fn handle(
&self,
myself: ActorRef<Self>,
message: Self::Msg,
state: &mut Self::State,
) -> Result<(), ActorProcessingErr> {
if *state < 10u8 {
message.print();
cast!(myself, message.next())?;
*state += 1;
} else {
println!();
myself.stop(None);
// don't send another message, rather stop the agent after 10 iterations
}
Ok(())
}
}
#[tokio::main]
async fn main() {
let (_actor, handle) = Actor::spawn(None, PingPong, ())
.await
.expect("Failed to start ping-pong actor");
handle
.await
.expect("Ping-pong actor failed to exit properly");
}
出力されます
$ cargo run
ping..pong..ping..pong..ping..pong..ping..pong..ping..pong..
$
アクター間の通信手段は、メッセージを相互に渡すことです。開発者は、任意のメッセージタイプを定義できます。 によってサポートされます。4つの同時メッセージタイプがあり、優先的にリッスンされます。彼らです
Send + 'static
ractor
Signal::Kill
Ractorアクターは、ノード間接続+ノードの命名を管理するErlangのEPMDと同様に、アクターの分散プールを構築するためにも使用できます。私たちの実装では、分散アクターを容易にするためにractor_cluster
があります。
ractor
ractor_clusterその中に単一のメインタイプ、つまりプロセスのホストを表すものがあります。さらに、分散アクターを構築する際の開発者の効率を促進するために、いくつかのマクロと手続き型マクロがあります。に責任があります
NodeServer
node()
NodeServer
NodeSession
TcpListener
ただし、ノード相互接続のロジックの大部分は、
NodeSession
等。。
は、シリアル化されたメッセージのみを処理する本質的に型指定されていないアクターである を生成し、メッセージの逆シリアル化を元のシステムに任せることで、ローカルアクターをリモートシステムで使用できるようにします。また、保留中の RPC 要求を追跡して、応答時に要求と応答を照合します。一般的に標準外で使用することを意図していないsを具体的にサポートするために追加された特別な拡張ポイントがあります
NodeSession
RemoteActor
ractor
RemoteActor
Actor::spawn(Some("name".to_string()), MyActor).await
パターン。
すべてのアクターが同じように作成されるわけではないことに注意してください。アクターは、ネットワークリンクを介して送信されるメッセージタイプをサポートする必要があります。これは、すべてのメッセージがサポートする必要がある特性の特定のメソッドをオーバーライドすることによって行われます。Rustには特殊化サポートがないため、使用する場合は、クレート内のすべてのメッセージタイプの特性を派生させる必要があります。ただし、これをサポートするために、これをより痛みのないプロセスにするための手続き型マクロがいくつかあります
ractor::Message
ractor_cluster
ractor::Message
多くのアクターはローカル専用であり、ネットワークリンクを介してメッセージを送信する必要はありません。これは最も基本的なシナリオであり、この場合はデフォルトの特性実装で問題ありません。次の方法ですばやく導き出すことができます。
ractor::Message
use ractor_cluster::RactorMessage;
use ractor::RpcReplyPort;
#[derive(RactorMessage)]
enum MyBasicMessageType {
Cast1(String, u64),
Call1(u8, i64, RpcReplyPort<Vec<String>>),
}
これにより、手動で書き出すことなく、デフォルトの特性が実装されます。
ractor::Message
アクターでリモート処理をサポートする場合は、別の派生ステートメントを使用する必要があります。
use ractor_cluster::RactorClusterMessage;
use ractor::RpcReplyPort;
#[derive(RactorClusterMessage)]
enum MyBasicMessageType {
Cast1(String, u64),
#[rpc]
Call1(u8, i64, RpcReplyPort<Vec<String>>),
}
これにより、実装のためにかなりの量の基礎となる定型文が追加されます(自分で見てください!しかし、簡単な答えは、各列挙型バリアントは引数のバイト配列、バリアント名にシリアル化する必要があり、RPCの場合はバイト配列を受信するポートを与え、応答を逆シリアル化する必要があります。引数または応答型内の各型は、この値をバイト配列に書き込んでバイト配列からデコードできるという特性を実装する必要があります。メッセージ型定義 (protobuf) に使用している場合は、型に対してこれを自動実装するマクロがあります。
cargo expand
ractor_cluster::BytesConvertable
prost
ractor_cluster::derive_serialization_for_prost_type! {MyProtobufType}
それに加えて、あなたがするようにあなたの俳優を書くだけです。アクター自体は、定義した場所に存在し、他のクラスターからネットワークリンクを介して送信されたメッセージを受信できます。
の原作者は、ショーン・ローラー(@slawlor)、ディロン・ジョージ(@dillonrg)、エヴァン・オー(@afterdusk)です。貢献の詳細については、CONTRIBUTING.md を参照してください。
ractor
ractor
このプロジェクトはMITの下でライセンスされています。