not that I know :)
On Jan 20, 2013, at 10:27 AM, Ben Coman wrote:
>
> I am considering a use case where a complex UI rendering loop is linked to an Announcement, which is being fired rapidly (eg < 1ms), and overall system performance suffers. However the UI rendering loop really only needs to execute every 100ms since that is sufficient for a user to perceive an immediate response to their action. �So I have rolled-my-own way to achieve this for which I was looking for some feedback...
>
> 1. Is there any existing feature in Pharo I have missed that can limit the firing rate of an announcement ?
> 2. Would this be useful to others as a feature to ship with Pharo ? (so I don't have to roll-my-own, and it gets more experienced eyes to ensure its right :) )
> 3. General comments on my approach, improvements, alternatives.
>
> By way of a use case using Workspace, execute...
> -------------
> | announcer mainCount �uiCount |
> announcer := Announcer new. "RateLimitingAnnouncer new."
> mainCount := uiCount := 0.
> Transcript crShow: 'ui' ; tab; show: 'main' .
> announcer subscribe: AnnouncementMockA do:
> [ � � uiCount := uiCount + 1.
> � "Imagine a longer duration UI rendering loop here"
> � Transcript crShow: uiCount asString , ' � � � ' , mainCount asString.
> ].
> [ � �10000 timesRepeat:
> � [ � �mainCount := mainCount + 1.
> � � � "(Delay forMilliseconds: 1 ) wait."
> � � � �announcer announce: AnnouncementMockA new. � � � ]
> ] timeToRun .
> -------------
> With 'Announcer' this takes 10 seconds to execute with the last lines being...
> 9999 � � � 9999
> 10000 � � � 10000
>
> Replacing 'Announcer' with my own 'RateLimitingAnnouncer' listed below, this takes 20 milliseconds with the last lines being...
> ui � �main
> 1 � � � 1
> 2 � � � 10000
>
> Uncommenting the "Delay" takes 30 seconds for Announcer - and 15 seconds for RateLimitingAnnouncer with last lines of...
> 289 � � � 9935
> 290 � � � 10000
>
>
> Here is my code wrapping #announce: and #initialize...
> -----
> Announcer subclass: #RateLimitingAnnouncer
> � instanceVariableNames: 'maxRateMilliSeconds queuedCounts'
> � classVariableNames: ''
> � poolDictionaries: ''
> � category: 'LEKtrek-Core'
> -----
> RateLimitingAnnouncer >>initialize
> � super initialize .
> � maxRateMilliSeconds := 100.
> � queuedCounts := Dictionary new.
> -----
> RateLimitingAnnouncer >>announce: anAnnouncement
> � | announcementClass |
>
> � "Track how many announcements fired since reset at end of forked Delay"
> � announcementClass := anAnnouncement class.
> � queuedCounts at: announcementClass
> � � � ifPresent: [ :count | queuedCounts at: announcementClass put: count + 1 ]
> � � � ifAbsent: [ queuedCounts at: announcementClass put: 1 ].
>
> � "At first announcement since Delay'ed reset, forward this one and set up Delay to condense subsequent ones. " � � � ( (queuedCounts at: announcementClass) = 1 ) ifTrue:
> � [ � � � � �[ � �"fire one announcement only for any announcement arriving within delay period."
> � � � � � (Delay forMilliseconds: maxRateMilliSeconds) wait. � � � � � � �[ (queuedCounts at: announcementClass) > 1 ] whileTrue: � � � � � �[ � �"At least one announcement arrived before end of Delay. Forward one announcement only and repeat" � � � � � � � � �queuedCounts at: announcementClass put: 1.
> � � � � � � � super announce: anAnnouncement.
> � � � � � � � (Delay forMilliseconds: maxRateMilliSeconds) wait. � � � � � � �].
> � � � � � queuedCounts at: announcementClass put: 0.
> � � � ] fork. � � � � �^ super announce: anAnnouncement. � � � � �].
> -----
>
> cheers -ben
>
>