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 ?
not that I know :) > 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 > >
