Process>>restart

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Process>>restart

Ben Coman
Just sharing a passing thought so I don't forget it before I have time
to think more deeply on it.

Several parts of Pharo (like SHTextStyler) are designed to have a
background process running, and when new input arrives that process is
killed so another can be immediately started - and sometimes we seem
to end up with large amounts of zombie processes.

As I poke around Process>>terminate, I wonder if a different approach
would be to have a Process>>restart.  I see there is Context>>restart.

The starting the background process might look like...

    stylingProcess := [ [ "do stuff with nextData". self suspend ]
repeat ] forkAt: 30.

and the code in the main morphic priority 40 thread might look like...

   sylingProcess suspend.
   nextData := 'blah'.
   sylingProcess restart.

anyway, back to the grind for me,
cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Process>>restart

Max Leske
I like the idea. I implemented something similar recently and one of the real advantages is that you can kill (suspend, inspect, etc.) such a process. Fast spawning processes are very hard to debug (e.g. in the process browser).

Max

> On 24 Feb 2016, at 16:23, Ben Coman <[hidden email]> wrote:
>
> Just sharing a passing thought so I don't forget it before I have time
> to think more deeply on it.
>
> Several parts of Pharo (like SHTextStyler) are designed to have a
> background process running, and when new input arrives that process is
> killed so another can be immediately started - and sometimes we seem
> to end up with large amounts of zombie processes.
>
> As I poke around Process>>terminate, I wonder if a different approach
> would be to have a Process>>restart.  I see there is Context>>restart.
>
> The starting the background process might look like...
>
>    stylingProcess := [ [ "do stuff with nextData". self suspend ]
> repeat ] forkAt: 30.
>
> and the code in the main morphic priority 40 thread might look like...
>
>   sylingProcess suspend.
>   nextData := 'blah'.
>   sylingProcess restart.
>
> anyway, back to the grind for me,
> cheers -ben
>


Reply | Threaded
Open this post in threaded view
|

Re: Process>>restart

Eliot Miranda-2
In reply to this post by Ben Coman


On Wed, Feb 24, 2016 at 7:23 AM, Ben Coman <[hidden email]> wrote:
Just sharing a passing thought so I don't forget it before I have time
to think more deeply on it.

Several parts of Pharo (like SHTextStyler) are designed to have a
background process running, and when new input arrives that process is
killed so another can be immediately started - and sometimes we seem
to end up with large amounts of zombie processes.

As I poke around Process>>terminate, I wonder if a different approach
would be to have a Process>>restart.  I see there is Context>>restart.

The starting the background process might look like...

    stylingProcess := [ [ "do stuff with nextData". self suspend ]
repeat ] forkAt: 30.

and the code in the main morphic priority 40 thread might look like...

   sylingProcess suspend.
   nextData := 'blah'.
   sylingProcess restart.

Hi Ben, so I'm assuming restart differs from resume.  Am I right in thinking it cuts back the process to the "start"?  Is the start the block from which the process was spawned, the argument to fork or forkAt:?  
 
anyway, back to the grind for me,
cheers -ben
 
_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: Process>>restart

Ben Coman
On Thu, Feb 25, 2016 at 3:06 AM, Eliot Miranda <[hidden email]> wrote:

>
>
> On Wed, Feb 24, 2016 at 7:23 AM, Ben Coman <[hidden email]> wrote:
>>
>> Just sharing a passing thought so I don't forget it before I have time
>> to think more deeply on it.
>>
>> Several parts of Pharo (like SHTextStyler) are designed to have a
>> background process running, and when new input arrives that process is
>> killed so another can be immediately started - and sometimes we seem
>> to end up with large amounts of zombie processes.
>>
>> As I poke around Process>>terminate, I wonder if a different approach
>> would be to have a Process>>restart.  I see there is Context>>restart.
>>
>> The starting the background process might look like...
>>
>>     stylingProcess := [ [ "do stuff with nextData". self suspend ]
>> repeat ] forkAt: 30.
>>
>> and the code in the main morphic priority 40 thread might look like...
>>
>>    sylingProcess suspend.
>>    nextData := 'blah'.
>>    sylingProcess restart.
>
>
> Hi Ben, so I'm assuming restart differs from resume.  Am I right in thinking
> it cuts back the process to the "start"?  Is the start the block from which
> the process was spawned, the argument to fork or forkAt:?

Thats right.  Essentially like Exception>>retry, to do something like this...

    restart := false.
    workAvailable := Semaphore new.
    process :=
    [   [  Transcript crShow: 'At the start'.
            work := 0.
            [   work := work + 1.
                Transcript crShow: 'working on ' , work printString.
                1 second wait.
                work>8 ifTrue:
                [   [Transcript crShow: 'Work complete.'] fork.
                    workAvailable wait.
                    restart := true.
                ].
                restart ifTrue: [self error].
                work
            ] repeat.
        ] on: Error do: [:err| restart := false. err retry].
    ] newProcess name:'My Restartable Worker'.
    process resume.

    "later do..."
    restart := true.
    "or after work complete..."
    workAvailable signal.

    "later still do..."
    process terminate

...except being able to interrupt the process anytime,
i.e. not needing to wait to get to "restart ifTrue: [self error]."


btw, The requirement for the fork in "[Transcript crShow: 'Work
complete.'] fork"
is strange. Without it the semaphore does not wait, which seems a bug.

btw2, I needed to hack OCUndeclaredVariableWarning>>defaultAction to
stop the transcript being polluted by unknown playground variables. No
warranty on whether this is suitable to be permanent...
    className = 'UndefinedObject' ifFalse: [
         self methodNode selector ifNotNil: [self crTrace: className,
'>>', selector, ' ']
         ifNil: [self traceCr:''].
         self traceCr: '(' , varName , ' is Undeclared1) '.
     ].




On Thu, Feb 25, 2016 at 2:56 AM, Max Leske <[hidden email]> wrote:
> Fast spawning processes are very hard to debug (e.g. in the process browser).

This is exactly the use case I was thinking of.  Often they've been
and gone before you even know they are there.  Having a permanent
process aids discoverability of system background functionality.

cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Process>>restart

Eliot Miranda-2
Hi Ben,

On Wed, Feb 24, 2016 at 10:44 PM, Ben Coman <[hidden email]> wrote:
On Thu, Feb 25, 2016 at 3:06 AM, Eliot Miranda <[hidden email]> wrote:
>
>
> On Wed, Feb 24, 2016 at 7:23 AM, Ben Coman <[hidden email]> wrote:
>>
>> Just sharing a passing thought so I don't forget it before I have time
>> to think more deeply on it.
>>
>> Several parts of Pharo (like SHTextStyler) are designed to have a
>> background process running, and when new input arrives that process is
>> killed so another can be immediately started - and sometimes we seem
>> to end up with large amounts of zombie processes.
>>
>> As I poke around Process>>terminate, I wonder if a different approach
>> would be to have a Process>>restart.  I see there is Context>>restart.
>>
>> The starting the background process might look like...
>>
>>     stylingProcess := [ [ "do stuff with nextData". self suspend ]
>> repeat ] forkAt: 30.
>>
>> and the code in the main morphic priority 40 thread might look like...
>>
>>    sylingProcess suspend.
>>    nextData := 'blah'.
>>    sylingProcess restart.
>
>
> Hi Ben, so I'm assuming restart differs from resume.  Am I right in thinking
> it cuts back the process to the "start"?  Is the start the block from which
> the process was spawned, the argument to fork or forkAt:?

Thats right.  Essentially like Exception>>retry, to do something like this...

    restart := false.
    workAvailable := Semaphore new.
    process :=
    [   [  Transcript crShow: 'At the start'.
            work := 0.
            [   work := work + 1.
                Transcript crShow: 'working on ' , work printString.
                1 second wait.
                work>8 ifTrue:
                [   [Transcript crShow: 'Work complete.'] fork.
                    workAvailable wait.
                    restart := true.
                ].
                restart ifTrue: [self error].
                work
            ] repeat.
        ] on: Error do: [:err| restart := false. err retry].
    ] newProcess name:'My Restartable Worker'.
    process resume.

    "later do..."
    restart := true.
    "or after work complete..."
    workAvailable signal.

    "later still do..."
    process terminate

...except being able to interrupt the process anytime,
i.e. not needing to wait to get to "restart ifTrue: [self error]."

It can be built simply above signalException:.  So...

Process class methods for instance creation
forBlock: aBlockClosure priority: anInteger 
"Answer an instance of me that has suspended aContext at priority anInteger."

<primitive: 19> "Simulation guard"
| newProcess |
(newProcess := self new)
suspendedContext:
[[[newProcess result: aBlockClosure value.
  false]
on: ProcessRestart
do: [:ex| true]]
whileTrue.
"Since control is now at the bottom there is no need to terminate (which
runs unwinds) since all unwinds have been run.  Simply suspend.
Note that we must use this form rather than e.g. Processor suspendActive
so that isTerminated answers true.  isTerminated requires that if there is a
suspended context it is the bottom-most, but using a send would result in
the process's suspendedContext /not/ being the bottom-most."
newProcess suspend] asContext;
priority: anInteger.
^newProcess
 
Process methods for process state change
restart
self signalException: ProcessRestart


btw, The requirement for the fork in "[Transcript crShow: 'Work
complete.'] fork"
is strange. Without it the semaphore does not wait, which seems a bug.

Is there a missing yield somewhere?
 

btw2, I needed to hack OCUndeclaredVariableWarning>>defaultAction to
stop the transcript being polluted by unknown playground variables. No
warranty on whether this is suitable to be permanent...
    className = 'UndefinedObject' ifFalse: [
         self methodNode selector ifNotNil: [self crTrace: className,
'>>', selector, ' ']
         ifNil: [self traceCr:''].
         self traceCr: '(' , varName , ' is Undeclared1) '.
     ].




On Thu, Feb 25, 2016 at 2:56 AM, Max Leske <[hidden email]> wrote:
> Fast spawning processes are very hard to debug (e.g. in the process browser).

This is exactly the use case I was thinking of.  Often they've been
and gone before you even know they are there.  Having a permanent
process aids discoverability of system background functionality.

cheers -ben




--
_,,,^..^,,,_
best, Eliot