Поделиться через


Метод 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

TimeoutException

Создается в случае превышения времени ожидания.

Возвращаемое значение

Асинхронное вычисление (объект 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

Исправлены сведения о поведении при истечении времени ожидания.

Исправление ошибки содержимого.