|
Class: LazyFuture
ProtoObject
|
+--DelayedValue
|
+--Future
|
+--LazyFuture
- Package:
- stx:libbasic2
- Category:
- Kernel-Processes
- Version:
- rev:
1.4
date: 2023/06/08 13:58:30
- user: cg
- file: LazyFuture.st directory: libbasic2
- module: stx stc-classLibrary: libbasic2
- Author:
- cg
I represent an execution in progress, which will be needed some time
in the future (but usually not soon).
I will be enqueued into a list of futures which are evaluated in the background
sequentially by ONE background process.
However, if my value is asked for and I have not yet been already evaluated,
my job will be dequeued and evaluated immediately.
Use instances of me, if there are a huge number of futures to be processed,
because a normal future will create ONE process for each as soon as created,
and all those futures will fight for execution time.
(one example is a UI which needs to process many files but will need the results
later).
Block
Lazy
LazyValue
Future
private
-
enqueueJob: aBlock
-
JobQueue := AccessLock := nil
-
jobQueueProcessLoop
-
-
onValueRequested
-
my value is asked for BEFORE I have been evaluated by the JobProcessor;
take me out of the queue and compute my value NOW
-
signalSemaphoreAfterForked: aBlock
-
common code for all block:* methods.
Execute aBlock in parallel with whatever called me,
and ensure that my private semaphore is signalled at the end.
-
signalSemaphoreAfterForked: aBlock atPriority: prio
-
blocked
Notice, that the following will take 2 seconds
(then, all will print more or less the same time)
[ Delay waitForSeconds:2. Transcript showCR:'message 1' ] futureValue.
[ Delay waitForSeconds:2. Transcript showCR:'message 2' ] futureValue.
[ Delay waitForSeconds:2. Transcript showCR:'message 3' ] futureValue.
[ Delay waitForSeconds:2. Transcript showCR:'message 4' ] futureValue.
[ Delay waitForSeconds:2. Transcript showCR:'message 5' ] futureValue.
|
Notice, that the following will take 10 seconds
(only one background computation at a time)
|v1 v2 v3 v4 v5 v6|
v1 := [ Transcript showCR:e'{Timestamp now} eval 1...'. Delay waitForSeconds:2. 11 ] lazyFutureValue.
v2 := [ Transcript showCR:e'{Timestamp now} eval 2...'. Delay waitForSeconds:2. 22 ] lazyFutureValue.
v3 := [ Transcript showCR:e'{Timestamp now} eval 3...'. Delay waitForSeconds:2. 33 ] lazyFutureValue.
v4 := [ Transcript showCR:e'{Timestamp now} eval 4...'. Delay waitForSeconds:2. 44 ] lazyFutureValue.
v5 := [ Transcript showCR:e'{Timestamp now} eval 5...'. Delay waitForSeconds:2. 55 ] lazyFutureValue.
v6 := [ Transcript showCR:e'{Timestamp now} eval 6...'. Delay waitForSeconds:2. 66 ] lazyFutureValue.
'early value request for v6'.
Transcript showCR:e'{Timestamp now} v6: '; showCR:v6 value.
Delay waitForSeconds:5.
'early value request for v2'.
Transcript showCR:e'{Timestamp now} v2: '; showCR:v2 value.
Transcript showCR:e'{Timestamp now} v1: '; showCR:v1 value.
Transcript showCR:e'{Timestamp now} v2: '; showCR:v2 value.
Transcript showCR:e'{Timestamp now} v3: '; showCR:v3 value.
Transcript showCR:e'{Timestamp now} v4: '; showCR:v4 value.
Transcript showCR:e'{Timestamp now} v5: '; showCR:v5 value.
Transcript showCR:e'{Timestamp now} v6: '; showCR:v6 value.
|
Counter example:
Starts evaluating multiples factorials immediately;
this will create 100 background processes and severely slowdown the UI!
| facs |
facs := 1 to:100 collect:[:i |
[(100*i) factorial printString] futureValue.
].
Transcript showCR: 'evaluating factorials...'.
Dialog information:'You can do something useful now...'.
facs do:[:each | Transcript showCR: each ]
|
Better:
| facs |
facs := 1 to:100 collect:[:i |
[(100*i) factorial printString] lazyFutureValue.
].
Transcript showCR: 'evaluating factorials...'.
Dialog information:'You can do something useful now...'.
facs doWithIndex:[:each :idx | Transcript showCR: e'{idx}: {each}' ]
|
|