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