Gnumed.pycommon.gmWorkerThread

Package Gnumed :: Package pycommon :: Module gmWorkerThread |
[frames] | no frames]

# Source Code for Module Gnumed.pycommon.gmWorkerThread

      1  __doc__ = """GNUmed worker threads."""
      2  #=====================================================================
      3  __author__ = "K.Hilbert <karsten.hilbert@gmx.net>"
      4  __license__ = "GPL v2 or later"
      5
      6  import sys
      7  import logging
      8  import threading
      9  import datetime as dt
     10  import pickle
     11  import copy
     12
     13  # wx.CallAfter() does not seem to work with multiprocessing !
     14  #import multiprocessing
     15
     16
     17  if __name__ == '__main__':
     18          sys.path.insert(0, '../../')
     19
     20
     21  _log = logging.getLogger('gm.worker')
     22
     23  #=====================================================================
     24 -def execute_in_worker_thread(payload_function=None, payload_kwargs=None, completion_callback=None, worker_name=None):
     25          """Create a thread and have it execute <payload_function>.
     26
     27          <completion_callback> - if not None - better be prepared to
     28          receive the result of <payload_function>.
     29          """
     30          assert (callable(payload_function)), 'payload function <%s> is not callable' % payload_function
     31          assert ((completion_callback is None) or callable(completion_callback)), 'completion callback <%s> is not callable' % completion_callback
     32
     33          _log.debug('worker [%s]', worker_name)
     34          # try to decouple from calling thread
     35          try:
     36                  __payload_kwargs = copy.deepcopy(payload_kwargs)
     37          except (copy.error, pickle.PickleError):
     38                  _log.exeption('failed to copy.deepcopy(payload_kwargs): %s', payload_kwargs)
     39                  _log.error('using shallow copy and hoping for the best')
     40                  __payload_kwargs = copy.copy(payload_kwargs)
     41          worker_thread = None
     42
     43          #-------------------------------
     44          def _run_payload():
     45                  try:
     46                          if payload_kwargs is None:
     47                                  payload_result = payload_function()
     48                          else:
     49                                  payload_result = payload_function(**__payload_kwargs)
     50                          _log.debug('finished running payload function: %s', payload_function)
     51                  except Exception:
     52                          _log.exception('error running payload function: %s', payload_function)
     53                          return
     54
     55                  if completion_callback is None:
     56                          return
     57
     58                  try:
     59                          completion_callback(payload_result)
     60                          _log.debug('finished running completion callback')
     61                  except Exception:
     62                          _log.exception('error running completion callback: %s', completion_callback)
     63                  _log.info('worker thread [name=%s, PID=%s] shuts down', worker_thread.name, worker_thread.ident)
     64                  return
     65          #-------------------------------
     66
     67          if worker_name is None:
     68                  __thread_name = dt.datetime.now().strftime('%f-%S')
     69          else:
     70                  __thread_name = '%sThread-%s' % (
     71                          worker_name,
     72                          dt.datetime.now().strftime('%f')
     73                  )
     74          _log.debug('creating thread "%s"', __thread_name)
     75          _log.debug(' "%s" payload function: %s', __thread_name, payload_function)
     76          _log.debug(' "%s" results callback: %s', __thread_name, completion_callback)
     77          #worker_thread = multiprocessing.Process (
     78          worker_thread = threading.Thread (
     79                  target = _run_payload,
     80                  name = __thread_name
     81          )
     82          # we don't want hung workers to prevent us from exiting GNUmed
     83          worker_thread.daemon = True
     84          _log.info('starting thread "%s"', __thread_name)
     85          worker_thread.start()
     86          _log.debug(' "%s" ident (= PID): %s', worker_thread.name, worker_thread.ident)
     87          # from here on, another thread executes _run_payload()
     88          # which executes payload_function() and, eventually,
     89          # completion_callback() if available,
     90          # return thread ident so people can join() it if needed
     91          return worker_thread.ident
     92
     93  #=====================================================================
     94  # main
     95  #=====================================================================
     96  if __name__ == "__main__":
     97
     98          if len(sys.argv) < 2:
     99                  sys.exit()
    100
    101          if sys.argv[1] != 'test':
    102                  sys.exit()
    103
    104          import time
    105          import random
    106
    107          from Gnumed.pycommon import gmLog2
    108
    109 -        def test_print_dots(ident=None):
    110
    111                  def slowly_print_dots(info=None):
    112                          for i in range(5):
    113                                  print('* (#%s in %s)' % (i, info))
    114                                  time.sleep(1 + (random.random()*4))
    115                          return '%s' % time.localtime()
    116
    117                  def print_dot_end_time(time_str):
    118                          print('done: %s' % time_str)
    119
    120                  execute_in_worker_thread (
    121                          payload_function = slowly_print_dots,
    122                          payload_kwargs = {'info': ident},
    123                          completion_callback = print_dot_end_time
    124                  )
    125
    126          test_print_dots('A')
    127          test_print_dots('B')
    128