About the non-use of Announcer in Bloc

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
53 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

NorbertHartl

> Am 30.08.2016 um 06:38 schrieb Stephan Eggermont <[hidden email]>:
>
> On 29/08/16 22:37, Denis Kudriashov wrote:
>> It looks quite safe to not check anything because subscription items are
>> instances of AnnouncementSubscription which are created internally
>> inside Announcer during subscription
>
> We should probably do something special for 0 and 1 subscriptions.
>
I think for the 0 case we should think about instantiating the SubscriptionRegistry lazily. This would also mitigate the effect that if a lot of announcers are created they create only a single object instead of two until used. Of course this depends on the probability of having a lot of announcers where only a few are used.
The #announce: method looks like it has been lazy before.

Announcer>>#announce: anAnnouncement

        | announcement |
        announcement := anAnnouncement asAnnouncement.
        registry ifNotNil: [
                registry deliver: announcement
                ].
        ^ announcement

checks for #ifNotNil: but registry is created in #initialize. So #ifNotEmpty: would be right here but #deliver: checks that, too.

For the 1 case we could store a single subscription in the registry field. Both subscription and registry have the #deliver: method so this would work out of the box. We could just dispatch the method.

So without having measured it myself it could be good if

- registry is nil if no subscribers are present. With nil checks the Announcer code could go fast
- registry is a subscription in case of 1 subscriber. No need for #subscriptionsHandling: because check is directly on the subscription for #handlesAnnouncement: This should save some cycles and the creation of intermediate collections. With not using the SubscriptionRegistry there is also no #critical: section saving the creation of one.
- registry is SubscriptionRegistry in case of >1 subscribers

my two cents,

Norbert



Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov
Hi

2016-08-30 8:52 GMT+02:00 Norbert Hartl <[hidden email]>:
I think for the 0 case we should think about instantiating the SubscriptionRegistry lazily. This would also mitigate the effect that if a lot of announcers are created they create only a single object instead of two until used. Of course this depends on the probability of having a lot of announcers where only a few are used.
The #announce: method looks like it has been lazy before.

Announcer>>#announce: anAnnouncement

        | announcement |
        announcement := anAnnouncement asAnnouncement.
        registry ifNotNil: [
                registry deliver: announcement
                ].
        ^ announcement

checks for #ifNotNil: but registry is created in #initialize. So #ifNotEmpty: would be right here but #deliver: checks that, too.

We always hide announcer instance inside owner. So it could instantiate announcer lazily if such optimization really needed.
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov

2016-08-30 9:44 GMT+02:00 Denis Kudriashov <[hidden email]>:

2016-08-30 8:52 GMT+02:00 Norbert Hartl <[hidden email]>:
I think for the 0 case we should think about instantiating the SubscriptionRegistry lazily. This would also mitigate the effect that if a lot of announcers are created they create only a single object instead of two until used. Of course this depends on the probability of having a lot of announcers where only a few are used.
The #announce: method looks like it has been lazy before.

Announcer>>#announce: anAnnouncement

        | announcement |
        announcement := anAnnouncement asAnnouncement.
        registry ifNotNil: [
                registry deliver: announcement
                ].
        ^ announcement

checks for #ifNotNil: but registry is created in #initialize. So #ifNotEmpty: would be right here but #deliver: checks that, too.

We always hide announcer instance inside owner. So it could instantiate announcer lazily if such optimization really needed.

Interesting is slots allow to implement such pattern?
I imagine AnnouncerSlot which will generate "read code" specifically depending on following message send.

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier
In reply to this post by Denis Kudriashov


2016-08-30 9:44 GMT+02:00 Denis Kudriashov <[hidden email]>:
Hi

2016-08-30 8:52 GMT+02:00 Norbert Hartl <[hidden email]>:
I think for the 0 case we should think about instantiating the SubscriptionRegistry lazily. This would also mitigate the effect that if a lot of announcers are created they create only a single object instead of two until used. Of course this depends on the probability of having a lot of announcers where only a few are used.
The #announce: method looks like it has been lazy before.

Announcer>>#announce: anAnnouncement

        | announcement |
        announcement := anAnnouncement asAnnouncement.
        registry ifNotNil: [
                registry deliver: announcement
                ].
        ^ announcement

checks for #ifNotNil: but registry is created in #initialize. So #ifNotEmpty: would be right here but #deliver: checks that, too.

We always hide announcer instance inside owner. So it could instantiate announcer lazily if such optimization really needed.

I remember making sure this was the case for Morph instances. If no subscriber, no announcer and make sure announcing something doesn't create the announcer lazily.

Thierry
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Guillermo Polito
Hi,

 From the top of my head: I would understand that systems where there
are hundreds of thousands of events per second, maybe one does not want
to pay the overhead of announcements...

But, How many events are produced from a morph per second? One? Two?
Five? Is it really the case of morphs the one that require optimization?

-------- Original Message --------

>
>
> 2016-08-30 9:44 GMT+02:00 Denis Kudriashov <[hidden email]
> <mailto:[hidden email]>>:
>
>     Hi
>
>     2016-08-30 8:52 GMT+02:00 Norbert Hartl <[hidden email]
>     <mailto:[hidden email]>>:
>
>         I think for the 0 case we should think about instantiating the
>         SubscriptionRegistry lazily. This would also mitigate the
>         effect that if a lot of announcers are created they create
>         only a single object instead of two until used. Of course this
>         depends on the probability of having a lot of announcers where
>         only a few are used.
>         The #announce: method looks like it has been lazy before.
>
>         Announcer>>#announce: anAnnouncement
>
>                 | announcement |
>                 announcement := anAnnouncement asAnnouncement.
>                 registry ifNotNil: [
>                         registry deliver: announcement
>                         ].
>                 ^ announcement
>
>         checks for #ifNotNil: but registry is created in #initialize.
>         So #ifNotEmpty: would be right here but #deliver: checks that,
>         too.
>
>
>     We always hide announcer instance inside owner. So it could
>     instantiate announcer lazily if such optimization really needed.
>
>
> I remember making sure this was the case for Morph instances. If no
> subscriber, no announcer and make sure announcing something doesn't
> create the announcer lazily.
>
> Thierry


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov

2016-08-30 10:21 GMT+02:00 Guille Polito <[hidden email]>:
Hi,

From the top of my head: I would understand that systems where there are hundreds of thousands of events per second, maybe one does not want to pay the overhead of announcements...

But, How many events are produced from a morph per second? One? Two? Five? Is it really the case of morphs the one that require optimization?

I have similar feeling. But maybe Spec is nice example which could improved by such optimizations
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier


2016-08-30 10:28 GMT+02:00 Denis Kudriashov <[hidden email]>:

2016-08-30 10:21 GMT+02:00 Guille Polito <[hidden email]>:
Hi,

From the top of my head: I would understand that systems where there are hundreds of thousands of events per second, maybe one does not want to pay the overhead of announcements...

But, How many events are produced from a morph per second? One? Two? Five? Is it really the case of morphs the one that require optimization?

I have similar feeling. But maybe Spec is nice example which could improved by such optimizations

No. Announcers are not the problem in Spec

Thierry

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Guillermo Polito
One Morph <----> One Announcer

sounds bad in terms of memory consumption, yes. Maybe it makes more
sense something like

One Widged <----> One Announcer

But the problem is that today the line between Morphs and Widgets is not
clearly set. I hope Bloc/Bric helps on this.

-------- Original Message --------

>
>
> 2016-08-30 10:28 GMT+02:00 Denis Kudriashov <[hidden email]
> <mailto:[hidden email]>>:
>
>
>     2016-08-30 10:21 GMT+02:00 Guille Polito
>     <[hidden email] <mailto:[hidden email]>>:
>
>         Hi,
>
>         From the top of my head: I would understand that systems where
>         there are hundreds of thousands of events per second, maybe
>         one does not want to pay the overhead of announcements...
>
>         But, How many events are produced from a morph per second?
>         One? Two? Five? Is it really the case of morphs the one that
>         require optimization?
>
>
>     I have similar feeling. But maybe Spec is nice example which could
>     improved by such optimizations
>
>
> No. Announcers are not the problem in Spec
>
> Thierry
>


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

NorbertHartl
In reply to this post by Denis Kudriashov

Am 30.08.2016 um 09:44 schrieb Denis Kudriashov <[hidden email]>:

Hi

2016-08-30 8:52 GMT+02:00 Norbert Hartl <[hidden email]>:
I think for the 0 case we should think about instantiating the SubscriptionRegistry lazily. This would also mitigate the effect that if a lot of announcers are created they create only a single object instead of two until used. Of course this depends on the probability of having a lot of announcers where only a few are used.
The #announce: method looks like it has been lazy before.

Announcer>>#announce: anAnnouncement

        | announcement |
        announcement := anAnnouncement asAnnouncement.
        registry ifNotNil: [
                registry deliver: announcement
                ].
        ^ announcement

checks for #ifNotNil: but registry is created in #initialize. So #ifNotEmpty: would be right here but #deliver: checks that, too.

We always hide announcer instance inside owner. So it could instantiate announcer lazily if such optimization really needed.

That prevents creating an announcer until someone creates the announcer lazily. That does not mean there is a subscription, especially if there are announcements sent. Announcements are such a central component (we made it that way) that every useful optimization should be considered!

Norbert

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier


2016-08-30 10:41 GMT+02:00 Norbert Hartl <[hidden email]>:

Am 30.08.2016 um 09:44 schrieb Denis Kudriashov <[hidden email]>:

Hi

2016-08-30 8:52 GMT+02:00 Norbert Hartl <[hidden email]>:
I think for the 0 case we should think about instantiating the SubscriptionRegistry lazily. This would also mitigate the effect that if a lot of announcers are created they create only a single object instead of two until used. Of course this depends on the probability of having a lot of announcers where only a few are used.
The #announce: method looks like it has been lazy before.

Announcer>>#announce: anAnnouncement

        | announcement |
        announcement := anAnnouncement asAnnouncement.
        registry ifNotNil: [
                registry deliver: announcement
                ].
        ^ announcement

checks for #ifNotNil: but registry is created in #initialize. So #ifNotEmpty: would be right here but #deliver: checks that, too.

We always hide announcer instance inside owner. So it could instantiate announcer lazily if such optimization really needed.

That prevents creating an announcer until someone creates the announcer lazily. That does not mean there is a subscription, especially if there are announcements sent. Announcements are such a central component (we made it that way) that every useful optimization should be considered!

Agreed.

The slightly tricky part is effectively to ensure that sending an announcement doesn't lazily create the announcer.

But, overall, the code isn't that complex, so it is worth optimising for it (IMHO).

The software engineering issue is that the optimisation is done in the code using the announcer object (for example, Morph) and not in the Announcer instance itself, which would make the optimisation applied everywhere. However, the benefit is that you do it only in places where you think it is necessary, not everywhere for everybody. This optimisation will have a cost for some operations (*), and so it may not be suitable everywhere.

Thierry

(*) I'm thinking of subscriptions removal there. Useless to optimise that for Morphs, for example (it would be very rare to see an object subscribe to a Morph, then unsubscribe). However, for the system announcer, given the number of objects subscribing / unsubscribing to it, don't try to optimise the no subscribers case!



 

Norbert


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov
In reply to this post by Thierry Goubier

2016-08-30 10:35 GMT+02:00 Thierry Goubier <[hidden email]>:

2016-08-30 10:28 GMT+02:00 Denis Kudriashov <[hidden email]>:

2016-08-30 10:21 GMT+02:00 Guille Polito <[hidden email]>:
Hi,

From the top of my head: I would understand that systems where there are hundreds of thousands of events per second, maybe one does not want to pay the overhead of announcements...

But, How many events are produced from a morph per second? One? Two? Five? Is it really the case of morphs the one that require optimization?

I have similar feeling. But maybe Spec is nice example which could improved by such optimizations

No. Announcers are not the problem in Spec

I just saw that every property in Spec model's is kind of ValueHolder with announcer instance inside. And it is huge number. But I think in case of Spec they are always used. So laziness will not helps here. But optimisation for single subscriber could.
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier


2016-08-30 11:12 GMT+02:00 Denis Kudriashov <[hidden email]>:

2016-08-30 10:35 GMT+02:00 Thierry Goubier <[hidden email]>:

2016-08-30 10:28 GMT+02:00 Denis Kudriashov <[hidden email]>:

2016-08-30 10:21 GMT+02:00 Guille Polito <[hidden email]>:
Hi,

From the top of my head: I would understand that systems where there are hundreds of thousands of events per second, maybe one does not want to pay the overhead of announcements...

But, How many events are produced from a morph per second? One? Two? Five? Is it really the case of morphs the one that require optimization?

I have similar feeling. But maybe Spec is nice example which could improved by such optimizations

No. Announcers are not the problem in Spec

I just saw that every property in Spec model's is kind of ValueHolder with announcer instance inside. And it is huge number. But I think in case of Spec they are always used. So laziness will not helps here. But optimisation for single subscriber could.

You're right. But I would consider making the value holder itself lazy (leaving it nil unless the model manipulates that property) so that you don't have to subscribe to a property which is never changed (and on the fly subscribe to it if it is lazily created by the model manipulation... could be a tad complex that one).

Thierry

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Henrik Sperre Johansen
In reply to this post by Denis Kudriashov

On 29 Aug 2016, at 6:39 , Denis Kudriashov <[hidden email]> wrote:

And now question is why SubscriptionRegistry manages subscriptions as IdentitySet instead of OrderedCollection? 

1) Performance of remove operation is the main reason. Sure, registration has a larger constant overhead than using an OrderedCollection, but it's still a theta(1) operation.Removal however, is theta(1)'ish, while with OrderedCollection, it would be theta(n/2). So for a general implementation where the usage pattern is unknown, it gives more balanced performance considering all use cases. *
2) Lessen chance of user relying on delivery order implied by registration order.

And yes, it's possible to create much better performing announcers for specific use patterns, such as a (short-lived) announcer where there's a period of registration, followed by a period of delivery, before eventual garbage collection of the announcer rather than explicit deregistration.
Personally, I think the (original) announcer pattern, where subscription collection is copied at registration, then replaced atomically, would be a better alternative.
You'd still need a mutex for the copy->add part to keep it thread-safe, but delivery would have much less overhead (no copy needed to avoid mutex guarding against mutation)

I'd be *very* wary of adding announcers that do not have thread-safe interaction between registration and delivery, though one suited for registration limited to a single thread may be a valid scenario.

Cheers,
Henry

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier


2016-08-30 16:01 GMT+02:00 Henrik Johansen <[hidden email]>:

On 29 Aug 2016, at 6:39 , Denis Kudriashov <[hidden email]> wrote:

And now question is why SubscriptionRegistry manages subscriptions as IdentitySet instead of OrderedCollection? 

1) Performance of remove operation is the main reason. Sure, registration has a larger constant overhead than using an OrderedCollection, but it's still a theta(1) operation.Removal however, is theta(1)'ish, while with OrderedCollection, it would be theta(n/2). So for a general implementation where the usage pattern is unknown, it gives more balanced performance considering all use cases. *
2) Lessen chance of user relying on delivery order implied by registration order.

And yes, it's possible to create much better performing announcers for specific use patterns, such as a (short-lived) announcer where there's a period of registration, followed by a period of delivery, before eventual garbage collection of the announcer rather than explicit deregistration.
Personally, I think the (original) announcer pattern, where subscription collection is copied at registration, then replaced atomically, would be a better alternative.
You'd still need a mutex for the copy->add part to keep it thread-safe, but delivery would have much less overhead (no copy needed to avoid mutex guarding against mutation)

I'd be *very* wary of adding announcers that do not have thread-safe interaction between registration and delivery, though one suited for registration limited to a single thread may be a valid scenario.

The problem I see with that scenario is the risk of code evolution and the fact one must be aware, in the announcement listener, that single threading is to be maintained... and this is out of the scope of the Announcer code itself (or even the object creating the announcer instance).

I have the same concern with an Announcer optimized for certain use cases, in the fact that the announcer creator is the one choosing the 'kind of' optimisation it would target, hoping that the listeners will conform to that use case...

Regards,

Thierry
 

Cheers,
Henry

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Henrik Sperre Johansen

> On 30 Aug 2016, at 5:16 , Thierry Goubier <[hidden email]> wrote:
>
>
> I have the same concern with an Announcer optimized for certain use cases, in the fact that the announcer creator is the one choosing the 'kind of' optimisation it would target, hoping that the listeners will conform to that use case...


There simply is no silver bullet that will give unbeatable performance in all scenarios; and focusing on improving one facet of the default implementation will inevitably lead to either
- the loss of some important property (general thread-safety if removing the mutex protection, ability to unsubscribe in handler if removing the copy operation and extending the delivery mutex protection, etc.)
- greatly degenerated performance for another facet (like #remove for OC's).

That said, the current implementation is very geared towards decent, balanced subscribe/unsubscribe performance, at the expense of delivery speed.
I've said it before, and still think, that offering at least one other implementation emphasizing delivery speed over subscription/unsubscription performance, in the same way the original implementation did (and/or changing the default Announcer to switch between the two dynamically based on heuristics) *would* be a valuable addition to the general library.

Cheers,
Henry


signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier


2016-08-30 17:36 GMT+02:00 Henrik Johansen <[hidden email]>:

> On 30 Aug 2016, at 5:16 , Thierry Goubier <[hidden email]> wrote:
>
>
> I have the same concern with an Announcer optimized for certain use cases, in the fact that the announcer creator is the one choosing the 'kind of' optimisation it would target, hoping that the listeners will conform to that use case...


There simply is no silver bullet that will give unbeatable performance in all scenarios; and focusing on improving one facet of the default implementation will inevitably lead to either
- the loss of some important property (general thread-safety if removing the mutex protection, ability to unsubscribe in handler if removing the copy operation and extending the delivery mutex protection, etc.)
- greatly degenerated performance for another facet (like #remove for OC's).

That said, the current implementation is very geared towards decent, balanced subscribe/unsubscribe performance, at the expense of delivery speed.
I've said it before, and still think, that offering at least one other implementation emphasizing delivery speed over subscription/unsubscription performance, in the same way the original implementation did (and/or changing the default Announcer to switch between the two dynamically based on heuristics) *would* be a valuable addition to the general library.

Intuitively, I would say that delivery speed would be more important. But I wonder what would be a way to ensure we optimise for the correct usual use. Either way, I agree with you about the interest of another implementation targetting faster delivery.

Regards,

Thierry


Cheers,
Henry


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier
In reply to this post by Henrik Sperre Johansen
Numbers for the discussion:

No activity, empty desktop:
announcements 608/minute
subscribe add/remove 9/minute

Activity, AltBrowser:
announcements 1109/minute
subscribe add/remove 207/minute

Activity, Nautilus:
announcements 2488/minute
subscribe add/remove 716/minute

Empirically the same processus in both environments: open two system
browser, in one, find the Announcer class, browse through a few of the
methods, select basicSubscribe: and ask for senders.

Tracing done with Metalinks during one minute.

Not exactly what I would have expected, especially the ratio subscribe
add/remove and announcements.

Thierry

Le 30/08/2016 à 17:36, Henrik Johansen a écrit :

>
>> On 30 Aug 2016, at 5:16 , Thierry Goubier
>> <[hidden email]> wrote:
>>
>>
>> I have the same concern with an Announcer optimized for certain use
>> cases, in the fact that the announcer creator is the one choosing
>> the 'kind of' optimisation it would target, hoping that the
>> listeners will conform to that use case...
>
>
> There simply is no silver bullet that will give unbeatable
> performance in all scenarios; and focusing on improving one facet of
> the default implementation will inevitably lead to either - the loss
> of some important property (general thread-safety if removing the
> mutex protection, ability to unsubscribe in handler if removing the
> copy operation and extending the delivery mutex protection, etc.) -
> greatly degenerated performance for another facet (like #remove for
> OC's).
>
> That said, the current implementation is very geared towards decent,
> balanced subscribe/unsubscribe performance, at the expense of
> delivery speed. I've said it before, and still think, that offering
> at least one other implementation emphasizing delivery speed over
> subscription/unsubscription performance, in the same way the original
> implementation did (and/or changing the default Announcer to switch
> between the two dynamically based on heuristics) *would* be a
> valuable addition to the general library.
>
> Cheers, Henry
>


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Glenn Cavarlé
Hi all (I was out for some days),

What i see is that Bloc EventRegistry:
1) is not thread safe (no mutex + #select:thenDo:)
2) doesn't allow handler removal from the handler list currently used in the thenDo: loop
3) is used specifically for a one-to-many communication (1 BlElement -> X handlers)
 
The (1) doesn't seem to be a problem in Bloc during UI event processing because a new event handler, even if it is added from another thread, would be taken into account for the next event. I note that it is really not recommended (at all) to update an UI element elsewhere than in the UI thread and it is like that in all other UI frameworks i know.

The (2) is a very specific use case and i don't know if it is a real need in Bloc because this implies that an element has 2 handlers for the same event and one of them has to remove the other before it is executed and during the same event processing (maybe more a conception issue than a common use case...). In other cases, no problem for handler removal.

But maybe i miss some specific cases in (1) and in (2).

To me, Announcer is really usefull and efficient when it is used as an event bus that can be shared between multiple objects.
For instance, it seems to be useless to use an Announcer in NewValueHolder because it cannot be shared and it is only used internally to register handlers and to propagate only the same event (ValueChanged) to them. What is the gain of using a full featured Announcer in this case?

In Bloc the constraint is to propagate more than 2000 events/second without to decrease fps, so we cannot afford to x4 the time to process events even if Announcer is safer and better tested.

Regards,
Glenn.
Glenn Cavarlé
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov

2016-08-31 10:10 GMT+02:00 Glenn Cavarlé <[hidden email]>:
Hi all (I was out for some days),

Hi Glenn
 

What i see is that Bloc EventRegistry:
1) is not thread safe (no mutex + #select:thenDo:)
2) doesn't allow handler removal from the handler list currently used in the
thenDo: loop
3) is used specifically for a one-to-many communication (1 BlElement -> X
handlers)

The (1) doesn't seem to be a problem in Bloc during UI event processing
because a new event handler, even if it is added from another thread, would
be taken into account for the next event.

Problem that concurrent modification of OrderedCollection could just fail. You will got debugger.
 
I note that it is really not
recommended (at all) to update an UI element elsewhere than in the UI thread
and it is like that in all other UI frameworks i know.

Does it means that I should not subscribe on UI events from different (not UI) processes?
How to do this if it is needed? 
Should I always put subscription code into #defer: message (analogue)? 
In that case what to do if I need to be sure that I really subscribe on event and only after this continue my business logic process?
 

The (2) is a very specific use case and i don't know if it is a real need in
Bloc because this implies that an element has 2 handlers for the same event
and one of them has to remove the other before it is executed and during the
same event processing (maybe more a conception issue than a common use
case...). In other cases, no problem for handler removal.

Very simple example: I want one shot handler for MouseMove to highlight element once to see that my mouse was moved around.
So my handler will highlight target element and unsubscribe it immediately.
Problem that if you do it on OrderedCollection during iteration you could skip one of the handlers. And probably some failures are also possible (debugger again).

Of course you could say users do not do all of this. But what the alternative? And if people will do this by "incident" it will be very difficult to discover reasons.
 

But maybe i miss some specific cases in (1) and in (2).

To me, Announcer is really usefull and efficient when it is used as an event
bus that can be shared between multiple objects.
For instance, it seems to be useless to use an Announcer in NewValueHolder
because it cannot be shared and it is only used internally to register
handlers and to propagate only the same event (ValueChanged) to them. What
is the gain of using a full featured Announcer in this case?

But in practice we never share any announcer instance. We always hide it inside owner object. ValueHolder is not specific example.
Also ValueHolder is kind of active model for UI application which could be shared between different views. And when it will be modified in one view another view will be updated automatically.
 

In Bloc the constraint is to propagate more than 2000 events/second without
to decrease fps, so we cannot afford to x4 the time to process events even
if Announcer is safer and better tested.

I wondering what the source of this constraint? Does Morphic follows it? I guess not, but all Pharo works quite well with it. 

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Glenn Cavarlé
Hi Denis,
Problem that concurrent modification of OrderedCollection could just fail. You will got debugger.
Yes, effectively, if there are multiple threads that try to add an handler on the same element at the same time, this could just fail.
To me, it is not a problem, it is just a rule: the scene graph is not thread-safe.
When a developper have to do this kind of specific stuff, he has to know that it is really not recommended and that he has to manage concurrency by hand.
But yes, he could use #runLater:.
Maybe, Bloc will have to provide kind of Task (using TaskIt?) with a specific api to ease ui synchronization using concurrency (later).

In that case what to do if I need to be sure that I really subscribe on event and only after this continue my business logic process?
Weird use case, you mean that sometime your business behavior declared after a subscription needs that the subscription have to be called before continue?
Please can you be more explicit? For what i understand, it look like a workaround or a conception issue.

Very simple example: I want one shot handler for MouseMove to highlight element once to see that my mouse was moved around.
So my handler will highlight target element and unsubscribe it immediately.
Problem that if you do it on OrderedCollection during iteration you could skip one of the handlers. And probably some failures are also possible (debugger again).
Yes, thanks for pointing this issue, i didn't remember that #select:thenDo: uses the index at each iteration.
I will update that using (handlers select:[...]) do:[...] instead. Since #select: create a new collection, there should not be any problem.

But in practice we never share any announcer instance. We always hide it inside owner object. ValueHolder is not specific example.
Also ValueHolder is kind of active model for UI application which could be shared between different views. And when it will be modified in one view another view will be updated automatically.
I know what is a ValueHolder and how data binding is usefull in GUI.
I didn't say that NewValueHolder and Announcer are not good and i don't think that, i just asked myself about why the use of Announcer in NewValueHolder make it 5x slower only to ensure that it is thread-safe while in most cases, all stuff is done in one thread.
It is why i didn't use NewValueHolder in Bloc. (I commited tests between NewValueHolder and BlObservableProperty in Bloc-Tests).  

If performances was not a critical issue in Bloc, obviously i would have used NewValueHolder and Announcer because there are well done and well tested.

I wondering what the source of this constraint? Does Morphic follows it? I guess not, but all Pharo works quite well with it.
Just move you mouse quickly on screen and think about how many MouseMoveEvent are generated by the system.
Yes, Morphic follows it. Morphic doesn't use Announcer for UI events and concurrent modifications of a morph seems to be not thread-safe.
Glenn Cavarlé
123