Re: [F#] вызов подписчиков на событие асинхронно
От: desco США http://v2matveev.blogspot.com
Дата: 30.09.10 12:21
Оценка: 6 (1)
Здравствуйте, cadet354, Вы писали:

C>Доброго времени,

C>есть Event, на него подписываются делегаты, как вызвать их асинхронно.
C>Сейчас при trigger они вызываются последовательно, к тому же если один handler упадет с exception другие не будут вызваны вообще.
C>Может помочь в этом Rx ?

стандартный Event<_, _> такого точно не сумеет, насчет Rx не уверен, но тоже есть сомнения. IMO проще сделать свой вариант Event, навроде такого (функционал для поддержки работы из нескольких потоков добавлять самому по вкусу)

    type Invoker<'D, 'A> = delegate of 'D * obj * 'A -> unit
    type Event<'D, 'A when 'D :> Delegate and 'D : delegate<'A, unit> and 'D : null>() =
        static let invoker = Delegate.CreateDelegate(typeof<Invoker<'D, 'A>>, typeof<'D>.GetMethod("Invoke")) :?> Invoker<'D, 'A>
            
        let mutable multicast : 'D = null    
     
        member x.Trigger(sender:obj,args: 'A) =
            match multicast with
            | null -> ()
            | d -> invoker.Invoke(d, sender, args) // DelegateEvent uses: d.DynamicInvoke(args) |> ignore

        member x.TriggerAsync(sender : obj, args : 'A) = 
            let delegates = 
                match multicast with
                | null -> Array.empty
                | d -> d.GetInvocationList()
            delegates
                |> Seq.map (fun d -> async { invoker.Invoke(d :?> _, sender, args) } )
                |> Async.Parallel
                |> Async.Ignore
 
        member x.Publish =
            { new IDelegateEvent<'D> with
                member x.AddHandler(d) =
                    multicast <- System.Delegate.Combine(multicast, d) :?> 'D
                member x.RemoveHandler(d) =
                    multicast <- System.Delegate.Remove(multicast, d)  :?> 'D }


такая реализация будет как минимум быстрее стандартной, которая внутри для вызова делегата использует Delegate.DynamicInvoke
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.