The 1th part describes how F #, as a parallel and asynchronous language, supports lightweight response operations and gives two modes of CPU asynchronous parallel and I/O asynchronous parallelism.
Part 2nd describes how to obtain results from either an asynchronous calculation or a background calculated cell.
Mode 4: Your first agent
Let's observe the first asynchronous agent you create:
type Agent<'T> = MailboxProcessor<'T>
let agent =
Agent.Start(fun inbox ->
async { while true do
let! msg = inbox.Receive()
printfn "got message '%s'" msg } )
The agent constantly waits for messages asynchronously and prints them out. In this code, each message is a string, and the type of the agent is:
Agent. Post "Hello!"
This will print out:
Got message ' hello! '
You can also send more than one message:
for i in 1 .. 10000 do
agent.Post (sprintf "message %d" i)
This allows you to print out 10,000 messages.
You can assume that each proxy object contains a message queue (or pipeline) and responds when the message arrives. A delegate typically uses asynchronous loops to wait for messages and process them. As in the example above, the agent uses a while loop for processing.
Many readers may already be familiar with the agency. Like Erlang, it is based on proxy design (where it is called a process). And not long ago, one was based. NET platform of experimental hatching language, Axum, also pay attention to the importance of agent-based programming. Axum interacts with Agent design in F #, while other languages that contain lightweight threads also emphasize agent-based composition and design.
The example above creates a type abbreviation: Agent, which represents the memory based proxy type "MailboxProcessor" in the F # class library. You can also use this full name if you like, but I prefer the simple naming.
Your first batch of 100,000 agents
The proxy object is very lightweight because it is based on the asynchronous programming model of F #. For example, you can be in one. NET process to create hundreds or even more agents. For example, let's create 100,000 simple proxy objects:
let agents =
[ for i in 0 .. 100000 ->
Agent.Start(fun inbox ->
async { while true do
let! msg = inbox.Receive()
if i % 10000 = 0 then
printfn "agent %d got message '%s'" i msg } ) ]
You can send messages to each proxy object this way:
for agent in agents do
agent.Post "ping!
Each 10,000th proxy object prints information when it receives a message. This proxy collection is very fast when processing messages, just a few seconds. Agent and in-memory messages are handled very quickly.
Obviously, the agent is not with. NET threads--you cannot create 100,000 of threads in a single application (32-bit OS, even 1000 threads are too many). Instead, when the broker waits for the message, it actually behaves as a callback function, some object allocations, and the closures referenced by the broker, and so on. After the message is received, the agent's work is in a thread pool (by default.) NET thread pool) and executes it.
Although it is rare to have 100,000 agents, more than 2000 agents are normal. Then we will see some examples.