패키지, 저장소 및 앱 카테고리 검색

패키지 상세v0.11.0

actors

다트용 액터 모델 라이브러리입니다. Isolate를 쉽게 사용할 수 있도록 하는 다트의 `Isolate`에 대한 얇은 래퍼입니다.

AndroidiOSmacOSWindowsLinux
30일 다운로드
2.2천
좋아요
29
Pub 점수
160

패키지 설치

flutter pub add actors

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

Actors 패키지는 액터 모델을 구현함으로써 Isolate 사용을 간소화하는 Dart 라이브러리입니다. 가벼우면서 직관적인 인터페이스를 제공하여 고립된 실행 컨텍스트를 생성하고 관리할 수 있게 하며, 공유 상태 없이 안전한 동시 프로그래밍을 가능하게 합니다. 원시 Isolate의 복잡성을 추상화함으로써 개발자들이 액터 간에 비동기적으로 메시지를 전송할 수 있게 해주며, 반응성과 확장성이 뛰어난 애플리케이션 개발에 이상적입니다. 경쟁 조건의 위험이 최소화된 고병렬 처리가 필요한 상황에서 특히 유용합니다.

사용 사례

  • 백그라운드 처리를 사용한 반응형 UI 구축
  • 메시지 전달 동시성 구현
  • 메인 스레드를 차단하지 않고 오랜 실행 작업을 처리하는 방법
  • 모듈식이고 고립된 컴포넌트 만들기
  • 여러 개의 독립된 프로세스 간에 상태 관리

주요 기능

  • `Actor` 클래스를 사용한 간단한 배우 생성
  • `send` 및 `receive`를 통한 메시지 전달
  • 자동 오류 처리 및 격리
  • 동기 및 비동기 통신 지원
  • Dart의 Isolate API에 대한 경량 래퍼

적합한 대상

  • Dart 앱에서 안전한 동시성에 대한 개발자
  • 격리되고 비차단 작업이 필요한 프로젝트
  • 모듈형 및 조합 가능한 컴포넌트가 필요한 애플리케이션
  • 병행성에 액터 모델을 채택하는 팀
  • 복잡한 백그라운드 로직을 가진 플러터 앱

고려 사항

  • 액터 모델 개념을 이해해야 합니다
  • Dart의 Isolate 기반 동시성에 제한됨
  • 공유 메모리 시나리오에 적합하지 않습니다
  • 메시지 직렬화로 인한 성능 오버헤드
  • 격리가 작업에 적합한 도구일 때 가장 효과적입니다 (간단한 비동기 작업에는 적합하지 않음)

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

actors

Actors CI pub package

actors is a library that enables the use of the Actors Model in Dart.

It is a thin wrapper around Dart's Isolate (on Flutter and Dart VM) and Web Workers (on the Web - TODO) that makes them much easier to use.

Actor

To start an Actor is very easy. You create a Handler implementing the logic to handle messages within the Actor's Isolate, then create an Actor using it:

class Accumulator with Handler<int, int> {
  int _value;
  
  Accumulator([int initialValue = 0]): _value = initialValue;
  
  int handle(int n) => _value += n;
}

main() async {
  final actor = Actor.create(() => Accumulator(6));
  print(await actor.send(5)); // 11
  await actor.close();
}

If your actor does not maintain internal state, it can also be created from a function, or even a lambda:

int two(int n) => n * 2;

main() async {
  final actor = Actor.of(two);
  print(await actor.send(5)); // 10
  await actor.close();
}

As you can see, an Actor can send a message back to the caller asynchronously.

They can also send more than one message back by returning a Stream:

// A Handler that returns a Stream must use a StreamActor, not an Actor.
class StreamGenerator with Handler<int, Stream<int>> {
  @override
  Stream<int> handle(int message) {
    return Stream.fromIterable(Iterable.generate(message, (i) => i));
  }
}

main() async {
  // Create an StreamActor from a Handler that returns Stream.
  final actor = StreamActor.create(StreamGenerator.new);
  final stream = actor.send(2);
  await for (final item in stream) {
    print(item); // 0, 1
  }
  await actor.close();
}
Actor state

An actor can safely maintain internal state which cannot be reached by any other actors (as it resides in its own Dart Isolate in the DartVM - please notice that this does not hold on the web).

The actor's state can include anything, even Streams and open sockets, for example, except if the Handler is instantiated locally by using the Actor(Handler handler) constructor. For this reason, prefer to use either the Actor.of constructors to wrap functions, or the Actor.create(Handler Function()) constructor that ensures the Handler is not instantiated locally.

Initial state that requires asynchronous calls can be initialized in the Handler's init method. actors guarantees that an Actor will never be called to handle a message before its init method has successfully returned.

For example, an Actor which wraps a HttpServer could be initialized as shown below:

class HttpServerActor with Handler<Message, Answer> {
  late final HttpServer _server;
  final int port;

  HttpServerActor(this.port);

  // this method will only run in the Actor's own Isolate, so we can
  // create non-sendable state.
  @override
  Future<void> init() async {
    // binding a server with "shared: true" means that requests will be handled
    // by multiple Isolates if HttpServerActor is started on many Isolates (see ActorGroup). 
    _server = await HttpServer.bind(InternetAddress.loopbackIPv4, port, shared: true);
    unawaited(_serveRequests());
  }
  
  // ...
}

You can see the full example code at example/stateful_actor_example.dart.

Sending an Actor to another Actor

To send an Actor to another Actor is not possible directly, but you can send its Sendable object, which can be obtained by calling toSendable() (unfortunately, this does not currently work for StreamActor).

See the inter_actor_test test for an example where an Actor's sender function is given to another Actor via its constructor.

This enables a common pattern where many actors are given a reference to another actor which can aggregate their results in one place.

Notice that using a Sendable to send messages has a small performance overhead when compared to a plain Actor. For the big_messages benchmark, Actor messages' round trip is measured at ~21us VS 28us for Sendable (using a Macbook Air from 2019).

Actors themselves perform identically to using plain Isolates directly.

ActorGroup

ActorGroup allows several Actor instances to be grouped together, all based on the same Handler implementation, but executed according to one of the available strategies:

  • RoundRobin - send message to a single Actor, alternating which member of the group receives the message.
  • MultiHandler - send message to m Actors, wait for at least n successful answers.

RoundRobing is appropriate for cases where messages are CPU intensive to handle and there may be many of them.

MultiHandler is a way to achieve high reliability by duplicating effort, as not all Actors in the group may be healthy at all times. Having a few "backups" doing the same work on each message may be a good idea in case one or more of the expected receivers are likely to fail, as the system will still continue to work without issues as long as n actors remain healthy... Also, by sending the same message to several actors, the message might be received in different locations, making it much harder for it to be lost.

// create a group of 4 actors
final group = ActorGroup(Two(), size: 4);
print(await group.send(5)); // 10
group.close();

Messenger

The Messenger mixin is implemented by Actor, ActorGroup, and also LocalMessenger, which runs its Handler in the local Isolate.

Messenger<int, int> messenger;

// a Messenger can be local
messenger = LocalMessenger(Two());
print(await messenger.send(2)); // 4

// or it can be an Actor
messenger = Actor(Two());
print(await messenger.send(3)); // 6
messenger.close();

// or an ActorGroup
messenger = ActorGroup(Two(), size: 2);
print(await messenger.send(4)); // 8
print(await messenger.send(5)); // 10
messenger.close();

This makes it possible to write code that works the same whether the message is handled locally or in another Isolate.

More examples

카테고리

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.