Marco de actores para el óxido
Any tipo) Para usar actix , agregue esto a su Cargo.toml :
[ dependencies ]
actix = " 0.13 " Para usar Actix, primero debe crear un System .
fn main ( ) {
let system = actix :: System :: new ( ) ;
system . run ( ) ;
} Actix usa el tiempo de ejecución de Tokio. System::new() crea un nuevo bucle de eventos. System.run() inicia el bucle de eventos Tokio y terminará una vez que el actor System reciba el mensaje SystemExit .
Para definir un actor, debe definir una estructura e implementar el rasgo Actor .
use actix :: { Actor , Context , System } ;
struct MyActor ;
impl Actor for MyActor {
type Context = Context < Self > ;
fn started ( & mut self , _ctx : & mut Self :: Context ) {
println ! ( "I am alive!" ) ;
System :: current ( ) . stop ( ) ; // <- stop system
}
}
fn main ( ) {
let system = System :: new ( ) ;
let _addr = system . block_on ( async { MyActor . start ( ) } ) ;
system . run ( ) . unwrap ( ) ;
} Se logra un nuevo actor a través del start y create métodos del rasgo del actor. Proporciona varias formas diferentes de crear actores; Para más detalles, consulte los documentos. Puede implementar los métodos started , stopping y stopped del rasgo del actor. started se llama cuando el actor comienza y stopping cuando termina el actor. Consulte los documentos de la API para obtener más información sobre el ciclo de vida del actor.
Un actor se comunica con otro actor enviando mensajes. En Actix se escriben todos los mensajes. Definamos un mensaje Sum simple con dos parámetros usize y un actor que aceptará este mensaje y devolverá la suma de esos dos números. Aquí usamos el atributo #[actix::main] como una forma más fácil de iniciar nuestro System e impulsar nuestra función principal para Actor podamos fácilmente .await
use actix :: prelude :: * ;
// this is our Message
// we have to define the response type (rtype)
# [ derive ( Message ) ]
# [ rtype ( usize ) ]
struct Sum ( usize , usize ) ;
// Actor definition
struct Calculator ;
impl Actor for Calculator {
type Context = Context < Self > ;
}
// now we need to implement `Handler` on `Calculator` for the `Sum` message.
impl Handler < Sum > for Calculator {
type Result = usize ; // <- Message response type
fn handle ( & mut self , msg : Sum , _ctx : & mut Context < Self > ) -> Self :: Result {
msg . 0 + msg . 1
}
}
# [ actix :: main ] // <- starts the system and block until future resolves
async fn main ( ) {
let addr = Calculator . start ( ) ;
let res = addr . send ( Sum ( 10 , 5 ) ) . await ; // <- send message and get future for result
match res {
Ok ( result ) => println ! ( "SUM: {}" , result ) ,
_ => println ! ( "Communication to the actor has failed" ) ,
}
} Todas las comunicaciones con actores pasan por un objeto Addr . Puede do_send un mensaje sin esperar una respuesta, o puede send a un actor un mensaje específico. El rasgo Message define el tipo de resultado para un mensaje.
Es posible que haya notado que los métodos de los rasgos de Actor y Handler aceptan &mut self , por lo que puede almacenar cualquier cosa en un actor y mutarlo cuando sea necesario.
Los objetos de dirección requieren un tipo de actor, pero si solo queremos enviar un mensaje específico a un actor que pueda manejar el mensaje, podemos usar la interfaz Recipient . Creemos un nuevo actor que use Recipient .
use actix :: prelude :: * ;
use std :: time :: Duration ;
# [ derive ( Message ) ]
# [ rtype ( result = "()" ) ]
struct Ping {
pub id : usize ,
}
// Actor definition
struct Game {
counter : usize ,
name : String ,
recipient : Recipient < Ping > ,
}
impl Actor for Game {
type Context = Context < Game > ;
}
// simple message handler for Ping message
impl Handler < Ping > for Game {
type Result = ( ) ;
fn handle ( & mut self , msg : Ping , ctx : & mut Context < Self > ) {
self . counter += 1 ;
if self . counter > 10 {
System :: current ( ) . stop ( ) ;
} else {
println ! ( "[{0}] Ping received {1}" , self . name , msg . id ) ;
// wait 100 nanoseconds
ctx . run_later ( Duration :: new ( 0 , 100 ) , move |act , _| {
act . recipient . do_send ( Ping { id : msg . id + 1 } ) ;
} ) ;
}
}
}
fn main ( ) {
let system = System :: new ( ) ;
system . block_on ( async {
// To create a cyclic game link, we need to use a different constructor
// method to get access to its recipient before it starts.
let _game = Game :: create ( |ctx| {
// now we can get an address of the first actor and create the second actor
let addr = ctx . address ( ) ;
let addr2 = Game {
counter : 0 ,
name : String :: from ( "Game 2" ) ,
recipient : addr . recipient ( ) ,
}
. start ( ) ;
// let's start pings
addr2 . do_send ( Ping { id : 10 } ) ;
// now we can finally create first actor
Game {
counter : 0 ,
name : String :: from ( "Game 1" ) ,
recipient : addr2 . recipient ( ) ,
}
} ) ;
} ) ;
// let the actors all run until they've shut themselves down
system . run ( ) . unwrap ( ) ;
}Vea este ejemplo de chat que muestra un uso más integral en un servicio de cliente/servidor de red.
¡Todas las contribuciones son bienvenidas, si tiene una solicitud de función, no dude en abrir un problema!
Este proyecto tiene licencia bajo cualquiera de
a tu opción.
La contribución al repositorio de Actix se organiza bajo los términos del pacto contribuyente. El equipo de Actix promete intervenir para defender ese código de conducta.