法罗承诺:
Pharo promises:
今年早些时候,我在 Pharo Smalltalk 参与了一个 promises 项目。
这个想法是为了实现以下行为:
([ 30 seconds wait. 4 ]promiseValue )then: [ :a| Transcript crShow: a ].
这意味着 promise 将在后台等待 30 秒并打印在 Transcript 上。这不应导致 Pharo 用户界面冻结。
我下面的实现冻结了用户界面。为什么?
Class 实现承诺行为的承诺:
Object subclass: #Promise
instanceVariableNames: 'promiseValue promiseError promiseLock'
classVariableNames: ''
package: 'META-Project-[pgakuo]'
里面的方法classPromise
doesNotUnderstand: aMessage
^ self value
perform: aMessage selector
withArguments: aMessage arguments
then: aBlock
promiseLock isSignaled
ifTrue: [ ^ self ].
promiseLock wait.
promiseError
ifNotNil: [ promiseError
privHandlerContext: thisContext;
signal ].
aBlock value: promiseValue.
self value: aBlock
then: aBlock catch: anotherBlock
promiseLock isSignaled
ifFalse:
[ promiseLock wait.
promiseError ifNotNil: [ anotherBlock value: promiseError ].
promiseValue ifNotNil: [ aBlock value: promiseValue. self value: aBlock ]]
value
promiseLock isSignaled ifFalse: [ promiseLock wait ].
promiseError ifNotNil:
[ promiseError
privHandlerContext: thisContext;
signal ].
^promiseValue
value: aBlock
promiseLock := Semaphore new.
[
[[promiseValue := aBlock value]
on: Error do: [:err | promiseError := err]]
ensure: [promiseLock signal]] fork
并向 Blockclosure 添加了一种方法,使闭包使用 Promise 行为。
promiseValue
^ Promise new value: self
一个块被传递给一个Promise的实例,它被Promise>>value:执行,它使用fork在后台执行任务。但它似乎没有按预期工作
在游乐场工作时,您将在 UI 流程中工作。因此,您实际上是在用您的示例暂停 UI 进程。试试这个:
[ ([ 30 seconds wait. 4 ] promiseValue) then: [ :a |
Transcript crShow: a ] ] forkAt: Processor userBackgroundPriority.
编辑
由于原始表达式明确要求不锁定 UI,您应该做的是:
- 不要覆盖
#doesNotUnderstand:
你有一个选择:
评估承诺时总是分叉
由于进程调度和进程创建,这将产生开销。您还将丢失原始进程的上下文,除非您明确保存它(消耗内存,导致性能损失)
仅当当前进程是UI进程
时才fork
判断当前进程是否为UI进程简单快捷。这不是您通常会做的事情,但对于您的情况,我推荐这种方法。
我建议为 Promise
实施 class 辅助方法,例如Promise class>>value:
。这将使您能够将此特定案例与其余实施隔离开来。例如
value: aBlock
| instance |
instance := self new.
self isUIProcess
ifTrue: [ [ instance value: aBlock ] forkAt: Processor userBackgroundPriority ]
ifFalse: [ instance value: aBlock ].
^ instance
我解决的卡顿问题如下:
then: aBlock
promiseLock isSignaled
ifFalse:
[ promiseLock wait.
promiseValue ifNotNil: [ aBlock value: promiseValue ]] fork.
并且操场上的以下代码不会冻结 UI
[ 12 seconds wait. 12 ]promiseValue then: [ :a| Transcript crShow: a/2 ]
它在 12 秒未冻结后打印 6 UI
今年早些时候,我在 Pharo Smalltalk 参与了一个 promises 项目。 这个想法是为了实现以下行为:
([ 30 seconds wait. 4 ]promiseValue )then: [ :a| Transcript crShow: a ].
这意味着 promise 将在后台等待 30 秒并打印在 Transcript 上。这不应导致 Pharo 用户界面冻结。 我下面的实现冻结了用户界面。为什么?
Class 实现承诺行为的承诺:
Object subclass: #Promise
instanceVariableNames: 'promiseValue promiseError promiseLock'
classVariableNames: ''
package: 'META-Project-[pgakuo]'
里面的方法classPromise
doesNotUnderstand: aMessage
^ self value
perform: aMessage selector
withArguments: aMessage arguments
then: aBlock
promiseLock isSignaled
ifTrue: [ ^ self ].
promiseLock wait.
promiseError
ifNotNil: [ promiseError
privHandlerContext: thisContext;
signal ].
aBlock value: promiseValue.
self value: aBlock
then: aBlock catch: anotherBlock
promiseLock isSignaled
ifFalse:
[ promiseLock wait.
promiseError ifNotNil: [ anotherBlock value: promiseError ].
promiseValue ifNotNil: [ aBlock value: promiseValue. self value: aBlock ]]
value
promiseLock isSignaled ifFalse: [ promiseLock wait ].
promiseError ifNotNil:
[ promiseError
privHandlerContext: thisContext;
signal ].
^promiseValue
value: aBlock
promiseLock := Semaphore new.
[
[[promiseValue := aBlock value]
on: Error do: [:err | promiseError := err]]
ensure: [promiseLock signal]] fork
并向 Blockclosure 添加了一种方法,使闭包使用 Promise 行为。
promiseValue
^ Promise new value: self
一个块被传递给一个Promise的实例,它被Promise>>value:执行,它使用fork在后台执行任务。但它似乎没有按预期工作
在游乐场工作时,您将在 UI 流程中工作。因此,您实际上是在用您的示例暂停 UI 进程。试试这个:
[ ([ 30 seconds wait. 4 ] promiseValue) then: [ :a |
Transcript crShow: a ] ] forkAt: Processor userBackgroundPriority.
编辑
由于原始表达式明确要求不锁定 UI,您应该做的是:
- 不要覆盖
#doesNotUnderstand:
你有一个选择:
评估承诺时总是分叉
由于进程调度和进程创建,这将产生开销。您还将丢失原始进程的上下文,除非您明确保存它(消耗内存,导致性能损失)
仅当当前进程是UI进程
时才fork判断当前进程是否为UI进程简单快捷。这不是您通常会做的事情,但对于您的情况,我推荐这种方法。
我建议为
Promise
实施 class 辅助方法,例如Promise class>>value:
。这将使您能够将此特定案例与其余实施隔离开来。例如value: aBlock | instance | instance := self new. self isUIProcess ifTrue: [ [ instance value: aBlock ] forkAt: Processor userBackgroundPriority ] ifFalse: [ instance value: aBlock ]. ^ instance
我解决的卡顿问题如下:
then: aBlock
promiseLock isSignaled
ifFalse:
[ promiseLock wait.
promiseValue ifNotNil: [ aBlock value: promiseValue ]] fork.
并且操场上的以下代码不会冻结 UI
[ 12 seconds wait. 12 ]promiseValue then: [ :a| Transcript crShow: a/2 ]
它在 12 秒未冻结后打印 6 UI