代码之家  ›  专栏  ›  技术社区  ›  Gakuo

法罗承诺:

  •  3
  • Gakuo  · 技术社区  · 6 年前

    今年早些时候,我在Pharo Smalltalk做了一个promises项目。

    ([ 30 seconds wait. 4 ]promiseValue )then: [ :a| Transcript crShow: a ].
    

    这意味着承诺将在后台等待30秒并打印在成绩单上。这不会导致Pharo用户界面冻结。 我下面的实现冻结了用户界面。为什么?

    实现承诺行为的类承诺:

    Object subclass: #Promise
        instanceVariableNames: 'promiseValue promiseError promiseLock'
        classVariableNames: ''
        package: 'META-Project-[pgakuo]'
    

    类承诺中的方法

    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
    

    promiseValue
        ^ Promise  new value: self 
    

    块被传递给Promise的实例,并由Promise>>value执行:后者使用fork在后台执行任务。但似乎并没有达到预期的效果

    2 回复  |  直到 6 年前
        1
  •  3
  •   Max Leske Thomas Shelby    6 年前

    在操场上工作时,您将在UI进程中工作。因此,您可以通过示例有效地挂起UI进程。试试这个:

    [ ([ 30 seconds wait. 4 ] promiseValue) then: [ :a |
        Transcript crShow: a ] ] forkAt: Processor userBackgroundPriority.
    

    编辑

    由于原始表达式明确要求不锁定UI,所以您应该做的是:

    1. 不覆盖 #doesNotUnderstand:
    2. 你可以选择:

      1. 这将由于进程调度和进程创建而产生开销。您还将丢失原始进程的上下文,除非显式保存它(消耗内存,导致性能损失)

      2. 检查当前进程是否是UI进程是简单而快速的。这不是你通常会做的事,但对于你的情况,我建议你采用这种方法。

    3. Promise ,例如。 Promise class>>value:

      value: aBlock
      | instance |
      instance := self new.
      self isUIProcess
          ifTrue: [ [ instance value: aBlock ] forkAt: Processor userBackgroundPriority ]
          ifFalse: [ instance value: aBlock ].
      ^ instance
      
        2
  •  0
  •   Gakuo    6 年前

    我解决了冰冻问题如下:

    then: aBlock
        promiseLock isSignaled
            ifFalse:
                [ promiseLock wait.         
                promiseValue ifNotNil: [  aBlock value: promiseValue ]] fork. 
    

    并且下面的代码在playground上不会冻结UI

    [ 12 seconds wait. 12 ]promiseValue then: [ :a|  Transcript crShow: a/2 ]