Skip to content

Commit

Permalink
Hello example
Browse files Browse the repository at this point in the history
  • Loading branch information
Emil Koutanov committed Jan 28, 2024
1 parent 6ab4e89 commit 3f58aa5
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
11 changes: 11 additions & 0 deletions Actors/Troupe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,22 @@ private IEnumerable<Task> DrainTasks()
return members.Select(member => member.Drain());
}

/// <summary>
/// Creates a troupe from an iterator of <c>ISchedulable</c> elements.
/// </summary>
/// <param name="members">The schedulable instances.</param>
/// <returns>A new troupe.</returns>
public static Troupe Of(IEnumerable<ISchedulable> members)
{
return new Troupe(members.ToList());
}

/// <summary>
/// Creates a troupe from an iterator of possibly null <c>ISchedulable</c> elements, keeping only
/// the non-null ones.
/// </summary>
/// <param name="members">The schedulable instances, possibly containing null references.</param>
/// <returns>A new troupe.</returns>
public static Troupe OfNullable(IEnumerable<ISchedulable?> members)
{
return Of(members.Where(member => member is not null).Select(member => member!));
Expand Down
34 changes: 34 additions & 0 deletions Examples/Hello/Hello.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Actors;

namespace Examples.Hello;

/// <summary>
/// The classic example, where the "Hello World" string is streamed character-by-character to a
/// <c>Printer</c> actor.
///
/// The example demonstrates the basic <c>Actor</c> API and the order-preserving semantics of
/// an actor's <c>Inbox</c>
/// </summary>
public class Example
{
class Printer : Actor<char>
{
protected override Task Perform(Inbox inbox)
{
var ch = inbox.Receive();
Console.Write(ch);
return Task.CompletedTask;
}
}

public static async Task RunAsync()
{
Console.WriteLine("---\nRunning hello example");
var printer = new Printer();
foreach (var ch in "Hello World\n")
{
printer.Send(ch);
}
await printer.Drain();
}
}
1 change: 1 addition & 0 deletions Examples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ static async Task Main(string[] args)
{
var examples = new Dictionary<string, Func<Task>>()
{
{ "Hello", () => Examples.Hello.Example.RunAsync() },
{ "Echo", () => Examples.Echo.Example.RunAsync() },
{ "Throttle", () => Examples.Throttle.Example.RunAsync() },
{ "Counter", () => Examples.Counter.Example.RunAsync() },
Expand Down
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,33 @@

Actors are units of serial execution within a broader concurrent topology. They enable the safe construction of massively parallel applications without the traditional synchronization primitives (mutexes, semaphores, and so forth). These aren't needed because rather than communicating by sharing state, actors communicate by message passing.

An `Actor` implementation has a dedicated `Inbox` to which messages can be posted in a fire-and-forget fashion via its `Send()` method. They are subsequently delivered to the actor's `Perform()` method in the order of their submission.
# Hello World
An `Actor` implementation has a dedicated `Inbox` to which messages can be posted in a fire-and-forget fashion via its `Send()` method. They are subsequently delivered to the actor's `Perform()` method in the order of their submission. An actor consumes a message by calling `Receive()` on the inbox.

# Examples
Below is a classic example, where the "Hello World" string is streamed character-by-character to a simple `Printer` actor. It demonstrates the basic `Actor` API and the order-preserving semantics of an actor's `Inbox`.

```csharp
class Printer : Actor<char>
{
protected override Task Perform(Inbox inbox)
{
var ch = inbox.Receive();
Console.Write(ch);
return Task.CompletedTask;
}
}

var printer = new Printer();
foreach (var ch in "Hello World\n")
{
printer.Send(ch);
}
await printer.Drain();
```

`Actor` classes can be optionally typed with the message that the actor expects to receive, as in the above example. If the actor only expects one kind of message, extending the generic `Actor<M>` is recommended for added type safety. More complex actors that handle a variety of message types should extend the non-generic `Actor` variant and cast messages internally.

# More Examples
See the `Examples` project for a variety of typical actor use cases. Run all examples with

```sh
Expand Down

0 comments on commit 3f58aa5

Please sign in to comment.