Метод MailboxProcessor.Scan<'Msg,'T> (F#)
Сканирует сообщение, выполняя поиск по сообщениям в порядке поступления до тех пор, пока предоставленная функция не вернет значение Some. Остальные сообщения остаются в очереди.
Пространство имен/путь к модулю: Microsoft.FSharp.Control
Сборка: FSharp.Core (в FSharp.Core.dll)
// Signature:
member this.Scan : ('Msg -> Async<'T> option) * ?int -> Async<'T>
// Usage:
mailboxProcessor.Scan (scanner)
mailboxProcessor.Scan (scanner, timeout = timeout)
Параметры
scanner
Тип: 'Msg -> Async<'T> optionФункция, возвращающая значение None, если сообщение необходимо пропустить, или значение Some, если сообщение следует обработать и удалить из очереди.
timeout
Тип: intНеобязательное время ожидания в миллисекундах. По умолчанию устанавливается значение -1, что соответствует значению Infinite().
Исключения
Исключение |
Атрибут Condition |
---|---|
Создается в случае превышения времени ожидания. |
Возвращаемое значение
Асинхронное вычисление (объект Async), созданное функцией scanner из прочитанного сообщения.
Заметки
Этот метод предназначен для использования в теле агента. Для каждого агента в каждый момент времени может быть активно только одно средство чтения, поэтому активным может быть только один вызов Receive, TryReceive, Scan и (или) TryScan. Тело функции scanner заблокирован во время выполнения, но блокировка освобождается до выполнения асинхронного рабочего процесса.
Пример
В следующем примере показано, как использовать метод Scan. В этом коде агенты обработчика почтового ящика управляют сериями имитируемых заданий, которые выполняются и вычисляют результат.
open System
let numProcs = Environment.ProcessorCount
type Job<'Result> = int * Async<'Result>
// Request to run a job, or
// Completed notification (with proc id and jobId
type RequestMessage<'Result> =
| Request of Job<'Result>
| Completed of int * int
// Contains the id of the proc and the job
type RunMessage<'Result> = int * Job<'Result>
let random = System.Random()
// The program computes the Nth prime numbers for various
// values of N.
// This number determines how large values of N are.
let multiplier = 5000
// Generates mock jobs using Async.Sleep.
let createJob(id:int, computation, input:int) =
let job = async {
let result = computation(input)
return result
}
id, job
let execAgents = Array.zeroCreate<MailboxProcessor<RunMessage<_>>> numProcs
let controllerAgent = new MailboxProcessor<RequestMessage<_>>(fun inbox ->
// First try to identify an idle proc by calling tryFindIndex.
// If there is an idle proc, scan for a request and run it.
// If there is not an idle proc, scan for an idle notification.
// No timeout given, so scan may wait indefinitely either to receive
// a new request, or for a proc to signal that it's idle. Meanwhile,
// messages build up in the queue.
// An array indicating whether each proc is idle.
let idleStatus = Array.create numProcs true
let rec loop (count) =
async {
let idleId = Array.tryFindIndex (fun elem -> elem) idleStatus
match idleId with
| Some id ->
do! inbox.Scan(function | Request((jobId, _) as job) ->
Some(async {
idleStatus.[id] <- false
printfn "Job #%d submitted." jobId
execAgents.[id].Post(id, job) })
| Completed _ -> None)
| None ->
do! inbox.Scan(function | Request _ -> None
| Completed (id, jobId) ->
Some(async { idleStatus.[id] <- true }))
do! loop (count + 1)
}
loop 0)
for procId in 0 .. numProcs - 1 do
execAgents.[procId] <- new MailboxProcessor<RunMessage<_>>(fun inbox ->
let rec loop (count) =
async {
let! procId, (jobId, job) = inbox.Receive()
// Start the job
// Post to the controller inbox when complete.
// The exception and cancellation continuations are not used.
printfn "Job #%d started on procId %d." jobId procId
Async.Start(async {
let! result = job
printfn "Job #%d completed." jobId
printfn "Nth Prime for N = %d is %s." (multiplier*jobId) (result.ToString())
controllerAgent.Post(Completed(procId, jobId))
})
do! loop (count + 1)
}
loop 0)
execAgents.[procId].Start()
controllerAgent.Start()
let numJobs = 10
printfn "Number Of Logical Processors: %d" numProcs
let isprime number = number > 1 && Seq.forall (fun n -> number % n <> 0) { 2 .. number/2 }
let nthPrime n = Seq.initInfinite (fun n -> n)
|> Seq.filter (fun n -> isprime n)
|> Seq.nth (n - 1)
let rec loop (count) =
let jobId = (numJobs - count)
let job = createJob(jobId, (fun n -> nthPrime(n)), multiplier * jobId )
printfn "Requesting job #%d" jobId
controllerAgent.Post(Request(job))
// Delay
System.Threading.Thread.Sleep(1000);
match count with
| 0 -> ()
| _ -> loop (count - 1)
loop (numJobs - 1)
printfn "Done submitting jobs. Press Enter to exit when ready."
Console.ReadLine() |> ignore
Ниже представлен пример сеанса.
Платформы
Windows 7, Windows Vista с пакетом обновления 2 (SP2), Windows XP с пакетом обновления 3 (SP3), Windows XP x64 с пакетом обновления 2 (SP2), Windows Server 2008 R2, Windows Server 2008 с пакетом обновления 2 (SP2), Windows Server 2003 с пакетом обновления 2 (SP2)
Сведения о версии
Среда выполнения F#
Поддерживается в версиях 2.0, 4.0
Silverlight
Поддерживается в версии 3
См. также
Ссылки
Класс Control.MailboxProcessor<'Msg> (F#)
Пространство имен Microsoft.FSharp.Control (F#)
Журнал изменений
Дата |
Журнал |
Причина |
---|---|---|
Январь 2011 |
Добавлен пример кода. |
Улучшение информации. |
Апрель 2011 |
Исправлены сведения о поведении при истечении времени ожидания. |
Исправление ошибки содержимого. |