[F#] вызов подписчиков на событие асинхронно
От: cadet354 Россия
Дата: 30.09.10 10:24
Оценка:
Доброго времени,
есть Event, на него подписываются делегаты, как вызвать их асинхронно.
Сейчас при trigger они вызываются последовательно, к тому же если один handler упадет с exception другие не будут вызваны вообще.
Может помочь в этом Rx ?
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
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
Re[2]: [F#] вызов подписчиков на событие асинхронно
От: cadet354 Россия
Дата: 30.09.10 12:28
Оценка:
Здравствуйте, desco, Вы писали:



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

спасибо, не хотел свой велосипед писать, думал есть что стандартное.
D>
D>    type Invoker<'D, 'A> = delegate of 'D * obj * 'A -> unit
D>    type Event<'D, 'A when 'D :> Delegate and 'D : delegate<'A, unit> and 'D : null>() =
D>        static let invoker = Delegate.CreateDelegate(typeof<Invoker<'D, 'A>>, typeof<'D>.GetMethod("Invoke")) :?> Invoker<'D, 'A>
            
D>        let mutable multicast : 'D = null    
     
D>        member x.Trigger(sender:obj,args: 'A) =
D>            match multicast with
D>            | null -> ()
D>            | d -> invoker.Invoke(d, sender, args) // DelegateEvent uses: d.DynamicInvoke(args) |> ignore

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


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

я посмотрел стандартную имплементацию, со фразами workaround bug WP7
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.