Reliable destruction

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Pierre-Eric.Melchy@uni-konstanz.de

    #1

    Reliable destruction

    Hello,

    I have a class measurement representing a physical measurement.
    Different objects in this class represent laboratory equipment, which
    might raise an exception (e.g. overtemperature ).

    In any case the equipment has to be switched off after the experiment,
    since if a
    power supply stays in the on state for a prolonged time equipment may
    be
    destroyed. Switching off is done by invoking the destructors of the
    instruments.

    My measurement looks like this:

    class measurement:
    def __init__(self):
    self.setup()
    self.run()

    def setup(self):
    self.powerSuppl y=apparate.Powe rSupply()
    self.magnet=app arate.magnet() # Exception("Comm unication Error")
    self.thermo=app arate.thermomet er()
    # some 5 more instruments

    def run():
    for i in range(100)
    self.powerSuppl y.setCurrent(i) # Exception("Over current")
    self.magnet.set Field(0.5*i)


    Different measurements are executed in a script which might run
    overnight:
    If one measurement raises an exception the next one might still work
    and I don't
    want to loose the results from the following experiments.

    try:
    measurement()
    except:
    pass
    try:
    measurement2()
    except:
    pass


    An exception might be thrown anywhere in init or run if e.g. the
    PowerSupply
    overheats. Maybe an asynchronous event might happen, too (user
    interrupt with ^C but I might live without that if it is impossible to
    handle)

    My questions are:
    1) under normal conditions (no exceptions) is there a guarantee, that
    __del__ of
    all instruments is called at the end of measurement()?

    2) if an exception is thrown, will all instruments be deleted if the
    error
    occurs in run() ?
    (only the instruments already initialized if the error occurs
    in setup() )?

    I am using CPython (on WinXP) and there are no reference cycles between
    the instruments.

    I have to stress again that a reliable finalization is important and
    cannot wait
    until the interpreter shuts down.

    I have tried this and it seems to work but this is of course no
    guarantee.



    Many thanks

  • Benjamin Niemann

    #2
    Re: Reliable destruction

    Pierre-Eric.Melchy@uni-konstanz.de wrote:
    [color=blue]
    > Hello,
    >
    > I have a class measurement representing a physical measurement.
    > Different objects in this class represent laboratory equipment, which
    > might raise an exception (e.g. overtemperature ).
    >
    > In any case the equipment has to be switched off after the experiment,
    > since if a
    > power supply stays in the on state for a prolonged time equipment may
    > be
    > destroyed. Switching off is done by invoking the destructors of the
    > instruments.
    >
    > My measurement looks like this:
    >
    > class measurement:
    > def __init__(self):
    > self.setup()
    > self.run()
    >
    > def setup(self):
    > self.powerSuppl y=apparate.Powe rSupply()
    > self.magnet=app arate.magnet() # Exception("Comm unication Error")
    > self.thermo=app arate.thermomet er()
    > # some 5 more instruments
    >
    > def run():
    > for i in range(100)
    > self.powerSuppl y.setCurrent(i) # Exception("Over current")
    > self.magnet.set Field(0.5*i)
    >
    >
    > Different measurements are executed in a script which might run
    > overnight:
    > If one measurement raises an exception the next one might still work
    > and I don't
    > want to loose the results from the following experiments.
    >
    > try:
    > measurement()
    > except:
    > pass
    > try:
    > measurement2()
    > except:
    > pass
    >
    >
    > An exception might be thrown anywhere in init or run if e.g. the
    > PowerSupply
    > overheats. Maybe an asynchronous event might happen, too (user
    > interrupt with ^C but I might live without that if it is impossible to
    > handle)
    >
    > My questions are:
    > 1) under normal conditions (no exceptions) is there a guarantee, that
    > __del__ of
    > all instruments is called at the end of measurement()?
    >
    > 2) if an exception is thrown, will all instruments be deleted if the
    > error
    > occurs in run() ?
    > (only the instruments already initialized if the error occurs
    > in setup() )?
    >
    > I am using CPython (on WinXP) and there are no reference cycles between
    > the instruments.
    >
    > I have to stress again that a reliable finalization is important and
    > cannot wait
    > until the interpreter shuts down.
    >
    > I have tried this and it seems to work but this is of course no
    > guarantee.[/color]

    I would suggest an explicit tearDown() method

    try:
    m = measurement()
    try:
    m.setup()
    m.run()
    finally:
    m.tearDown()
    except KeyboardInterru pt:
    # user pressed ctrl-C
    print "***BREAK"
    sys.exit(1)
    except:
    # you should at least log the exception for later debugging
    traceback.print _exc()

    and remove the calls to setup() and run() from the constructor.

    --
    Benjamin Niemann
    Email: pink at odahoda dot de
    WWW: http://www.odahoda.de/

    Comment

    • Pierre-Eric.Melchy@uni-konstanz.de

      #3
      Re: Reliable destruction

      Hello Benjamin,

      What would happen if an exception was thrown in the middle of setup()?
      tearDown could not handle this case without having a list of the
      objects already constructed (Or I would have to rely on the automatic
      call to __del__, if it is reliable).


      There is still some problem:
      Imagine a communication error in run() which would cause del to fail on
      the instrument.
      Anyway, I think this case is still more difficult to handle.

      Comment

      • Benjamin Niemann

        #4
        Re: Reliable destruction

        Pierre-Eric.Melchy@uni-konstanz.de wrote:
        [color=blue]
        > Hello Benjamin,
        >
        > What would happen if an exception was thrown in the middle of setup()?
        > tearDown could not handle this case without having a list of the
        > objects already constructed (Or I would have to rely on the automatic
        > call to __del__, if it is reliable).[/color]

        class measurement:
        def __init__(self):
        self.powerSuppl y = None
        ...

        def setup(self):
        self.powerSuppl y=apparate.Powe rSupply()
        ...

        def tearDown(self):
        if self.powerSuppl y is not None:
        try:
        self.powerSuppl y.tearDown()
        except:
        # Exception in powerSupply.tea rDown() should not stop
        # the following tearDown()s from being executed
        traceback.print _exc()

        ...

        [color=blue]
        > There is still some problem:
        > Imagine a communication error in run() which would cause del to fail on
        > the instrument.[/color]

        Not really sure, if I understand what you mean? Does my tearDown() above
        covers this?
        [color=blue]
        > Anyway, I think this case is still more difficult to handle.[/color]

        Reliable, fail-safe software *is* hard to design and implement, that's for
        sure..
        Be happy that it's just a power supply that could overheat and not the core
        of a nuclear power plant.

        --
        Benjamin Niemann
        Email: pink at odahoda dot de
        WWW: http://www.odahoda.de/

        Comment

        • Raymond Hettinger

          #5
          Re: Reliable destruction

          [Pierre-Eric.Melchy@uni-konstanz.de][color=blue]
          > My questions are:
          > 1) under normal conditions (no exceptions) is there a guarantee, that
          > __del__ of
          > all instruments is called at the end of measurement()?
          >
          > 2) if an exception is thrown, will all instruments be deleted if the
          > error
          > occurs in run() ?
          > (only the instruments already initialized if the error occurs
          > in setup() )?
          >
          > I am using CPython (on WinXP) and there are no reference cycles between
          > the instruments.
          >
          > I have to stress again that a reliable finalization is important and
          > cannot wait
          > until the interpreter shuts down.
          >
          > I have tried this and it seems to work but this is of course no
          > guarantee.[/color]

          On the plus side, Python does guarantee destruction in the absence of
          cycles when the last reference disappears. If there is a cycle, you
          have to wait for GC. If you can't wait, then schedule a gc.collect()
          to run periodically.

          On the minus side, this is a somewhat brittle and error-prone design
          strategy. A single, accidental persistent reference is sufficient to
          cause failure -- that is a land-mine for all future maintainers of your
          code. It is better to make explicit tear-down calls and to wrap
          finalization is a try/finally suite.

          The simplified code in your post suggests that the instrument shut-off
          can be placed at the end of the run() method -- loosely translated as
          turn-off the lights when you're done.

          An alternative strategy is to periodically poll resources and shut them
          off if they are not in use -- loosely translated as having a security
          guard turn-off any coffee-pots that were left on by frazzled
          programmers as they leave at odd hours of the night.


          Raymond

          Comment

          • Pierre-Eric.Melchy@uni-konstanz.de

            #6
            Re: Reliable destruction

            Hello,

            your idea sounds good and handles the exception on teardown as well.
            (I did not think about the if XXX!=None check in teardown())
            I will now provide each of the instruments with an explicit shutdown()
            method which frees the interface card as well.

            These methods will be called in a finally clause after run.
            I think this is much better than to wait for or rely on garbage
            collection.

            Of course there is a hardware protection of the setup as well.

            I am amazed how well Python handles lab instrumentation , it is really
            fun to develop with Py.


            Many thanks for your help

            Comment

            Working...