def __repr__(self): try: if self._semlock._is_mine(): name = process.current_process().name if threads_new.current_thread().name != 'MainThread': name += '|' + threads_new.current_thread().name elif self._semlock._get_value() == 1: name = 'None' elif self._semlock._count() > 0: name = 'SomeOtherThread' else: name = 'SomeOtherProcess' except Exception: name = 'unknown' return '<%s(owner=%s)>' % (self.__class__.__name__, name)
def __init__(self, path, threaded=True, timeout=None): """ >>> lock = LockBase('somefile') >>> lock = LockBase('somefile', threaded=False) """ super(LockBase, self).__init__(path) self.lock_file = os.path.abspath(path) + ".lock" self.hostname = socket.gethostname() self.pid = os.getpid() if threaded: t = threads_new.current_thread() # Thread objects in Python 2.4 and earlier do not have ident # attrs. Worm around that. ident = getattr(t, "ident", hash(t)) self.tname = "-%x" % (ident & 0xffffffff) else: self.tname = "" dirname = os.path.dirname(self.lock_file) # unique name is mostly about the current process, but must # also contain the path -- otherwise, two adjacent locked # files conflict (one file gets locked, creating lock-file and # unique file, the other one gets locked, creating lock-file # and overwriting the already existing lock-file, then one # gets unlocked, deleting both lock-file and unique file, # finally the last lock errors out upon releasing. self.unique_name = os.path.join(dirname, "%s%s.%s%s" % (self.hostname, self.tname, self.pid, hash(self.path))) self.timeout = timeout
def concurrency_safe_write(object_to_write, filename, write_func): """Writes an object into a unique file in a concurrency-safe way.""" thread_id = id(threads_new.current_thread()) temporary_filename = '{}.thread-{}-pid-{}'.format(filename, thread_id, os.getpid()) write_func(object_to_write, temporary_filename) return temporary_filename
def _flag_current_thread_clean_exit(): """Put a ``_clean_exit`` flag on the current thread""" thread = threads_new.current_thread() thread._clean_exit = True
def in_main_thread(): return isinstance(threads_new.current_thread(), threads_new._MainThread)
def __call__(self, a): m = _get_backing_memmap(a) if m is not None and isinstance(m, np.memmap): # a is already backed by a memmap file, let's reuse it directly return _reduce_memmap_backed(a, m) if (not a.dtype.hasobject and self._max_nbytes is not None and a.nbytes > self._max_nbytes): # check that the folder exists (lazily create the pool temp folder # if required) try: os.makedirs(self._temp_folder) os.chmod(self._temp_folder, FOLDER_PERMISSIONS) except OSError as e: if e.errno != errno.EEXIST: raise e try: basename = self._memmaped_arrays.get(a) except KeyError: # Generate a new unique random filename. The process and thread # ids are only useful for debugging purpose and to make it # easier to cleanup orphaned files in case of hard process # kill (e.g. by "kill -9" or segfault). basename = "{}-{}-{}.pkl".format( os.getpid(), id(threads_new.current_thread()), uuid4().hex) self._memmaped_arrays.set(a, basename) filename = os.path.join(self._temp_folder, basename) # In case the same array with the same content is passed several # times to the pool subprocess children, serialize it only once # XXX: implement an explicit reference counting scheme to make it # possible to delete temporary files as soon as the workers are # done processing this data. if not os.path.exists(filename): if self.verbose > 0: print("Memmapping (shape={}, dtype={}) to new file {}". format(a.shape, a.dtype, filename)) for dumped_filename in dump(a, filename): os.chmod(dumped_filename, FILE_PERMISSIONS) if self._prewarm: # Warm up the data by accessing it. This operation ensures # that the disk access required to create the memmapping # file are performed in the reducing process and avoids # concurrent memmap creation in multiple children # processes. load(filename, mmap_mode=self._mmap_mode).max() elif self.verbose > 1: print("Memmapping (shape={}, dtype={}) to old file {}".format( a.shape, a.dtype, filename)) # The worker process will use joblib.load to memmap the data return (load, (filename, self._mmap_mode)) else: # do not convert a into memmap, let pickler do its usual copy with # the default system pickler if self.verbose > 1: print("Pickling array (shape={}, dtype={}).".format( a.shape, a.dtype)) return (loads, (dumps(a, protocol=HIGHEST_PROTOCOL), ))
def get_ident(): return threads_new.current_thread().ident
def exit(self): self.was_killed.set() if self is not current_thread(): self.join() return self.report()
def in_main_thread() -> bool: """ True when the current thread is the main thread. """ return threads_new.current_thread().__class__.__name__ == "_MainThread"