## Module providing the `Process` class which emulates `threading.Thread`## multiprocessing/process.py## Copyright (c) 2006-2008, R Oudkerk# Licensed to PSF under a Contributor Agreement.#__all__ = ['BaseProcess', 'current_process', 'active_children','parent_process']## Imports#import osimport sysimport signalimport itertoolsimport threadingfrom _weakrefset import WeakSet###try:ORIGINAL_DIR = os.path.abspath(os.getcwd())except OSError:ORIGINAL_DIR = None## Public functions#def current_process():'''Return process object representing the current process'''return _current_processdef active_children():'''Return list of process objects corresponding to live child processes'''_cleanup()return list(_children)def parent_process():'''Return process object representing the parent process'''return _parent_process###def _cleanup():# check for processes which have finishedfor p in list(_children):if p._popen.poll() is not None:_children.discard(p)## The `Process` class#class BaseProcess(object):'''Process objects represent activity that is run in a separate processThe class is analogous to `threading.Thread`'''def _Popen(self):raise NotImplementedErrordef __init__(self, group=None, target=None, name=None, args=(), kwargs={},*, daemon=None):assert group is None, 'group argument must be None for now'count = next(_process_counter)self._identity = _current_process._identity + (count,)self._config = _current_process._config.copy()self._parent_pid = os.getpid()self._parent_name = _current_process.nameself._popen = Noneself._closed = Falseself._target = targetself._args = tuple(args)self._kwargs = dict(kwargs)self._name = name or type(self).__name__ + '-' + \':'.join(str(i) for i in self._identity)if daemon is not None:self.daemon = daemon_dangling.add(self)def _check_closed(self):if self._closed:raise ValueError("process object is closed")def run(self):'''Method to be run in sub-process; can be overridden in sub-class'''if self._target:self._target(*self._args, **self._kwargs)def start(self):'''Start child process'''self._check_closed()assert self._popen is None, 'cannot start a process twice'assert self._parent_pid == os.getpid(), \'can only start a process object created by current process'assert not _current_process._config.get('daemon'), \'daemonic processes are not allowed to have children'_cleanup()self._popen = self._Popen(self)self._sentinel = self._popen.sentinel# Avoid a refcycle if the target function holds an indirect# reference to the process object (see bpo-30775)del self._target, self._args, self._kwargs_children.add(self)def terminate(self):'''Terminate process; sends SIGTERM signal or uses TerminateProcess()'''self._check_closed()self._popen.terminate()def kill(self):'''Terminate process; sends SIGKILL signal or uses TerminateProcess()'''self._check_closed()self._popen.kill()def join(self, timeout=None):'''Wait until child process terminates'''self._check_closed()assert self._parent_pid == os.getpid(), 'can only join a child process'assert self._popen is not None, 'can only join a started process'res = self._popen.wait(timeout)if res is not None:_children.discard(self)def is_alive(self):'''Return whether process is alive'''self._check_closed()if self is _current_process:return Trueassert self._parent_pid == os.getpid(), 'can only test a child process'if self._popen is None:return Falsereturncode = self._popen.poll()if returncode is None:return Trueelse:_children.discard(self)return Falsedef close(self):'''Close the Process object.This method releases resources held by the Process object. It isan error to call this method if the child process is still running.'''if self._popen is not None:if self._popen.poll() is None:raise ValueError("Cannot close a process while it is still running. ""You should first call join() or terminate().")self._popen.close()self._popen = Nonedel self._sentinel_children.discard(self)self._closed = True@propertydef name(self):return self._name@name.setterdef name(self, name):assert isinstance(name, str), 'name must be a string'self._name = name@propertydef daemon(self):'''Return whether process is a daemon'''return self._config.get('daemon', False)@daemon.setterdef daemon(self, daemonic):'''Set whether process is a daemon'''assert self._popen is None, 'process has already started'self._config['daemon'] = daemonic@propertydef authkey(self):return self._config['authkey']@authkey.setterdef authkey(self, authkey):'''Set authorization key of process'''self._config['authkey'] = AuthenticationString(authkey)@propertydef exitcode(self):'''Return exit code of process or `None` if it has yet to stop'''self._check_closed()if self._popen is None:return self._popenreturn self._popen.poll()@propertydef ident(self):'''Return identifier (PID) of process or `None` if it has yet to start'''self._check_closed()if self is _current_process:return os.getpid()else:return self._popen and self._popen.pidpid = ident@propertydef sentinel(self):'''Return a file descriptor (Unix) or handle (Windows) suitable forwaiting for process termination.'''self._check_closed()try:return self._sentinelexcept AttributeError:raise ValueError("process not started") from Nonedef __repr__(self):exitcode = Noneif self is _current_process:status = 'started'elif self._closed:status = 'closed'elif self._parent_pid != os.getpid():status = 'unknown'elif self._popen is None:status = 'initial'else:exitcode = self._popen.poll()if exitcode is not None:status = 'stopped'else:status = 'started'info = [type(self).__name__, 'name=%r' % self._name]if self._popen is not None:info.append('pid=%s' % self._popen.pid)info.append('parent=%s' % self._parent_pid)info.append(status)if exitcode is not None:exitcode = _exitcode_to_name.get(exitcode, exitcode)info.append('exitcode=%s' % exitcode)if self.daemon:info.append('daemon')return '<%s>' % ' '.join(info)##def _bootstrap(self, parent_sentinel=None):from . import util, contextglobal _current_process, _parent_process, _process_counter, _childrentry:if self._start_method is not None:context._force_start_method(self._start_method)_process_counter = itertools.count(1)_children = set()util._close_stdin()old_process = _current_process_current_process = self_parent_process = _ParentProcess(self._parent_name, self._parent_pid, parent_sentinel)if threading._HAVE_THREAD_NATIVE_ID:threading.main_thread()._set_native_id()try:util._finalizer_registry.clear()util._run_after_forkers()finally:# delay finalization of the old process object until after# _run_after_forkers() is executeddel old_processutil.info('child process calling self.run()')try:self.run()exitcode = 0finally:util._exit_function()except SystemExit as e:if not e.args:exitcode = 1elif isinstance(e.args[0], int):exitcode = e.args[0]else:sys.stderr.write(str(e.args[0]) + '\n')exitcode = 1except:exitcode = 1import tracebacksys.stderr.write('Process %s:\n' % self.name)traceback.print_exc()finally:threading._shutdown()util.info('process exiting with exitcode %d' % exitcode)util._flush_std_streams()return exitcode## We subclass bytes to avoid accidental transmission of auth keys over network#class AuthenticationString(bytes):def __reduce__(self):from .context import get_spawning_popenif get_spawning_popen() is None:raise TypeError('Pickling an AuthenticationString object is ''disallowed for security reasons')return AuthenticationString, (bytes(self),)## Create object representing the parent process#class _ParentProcess(BaseProcess):def __init__(self, name, pid, sentinel):self._identity = ()self._name = nameself._pid = pidself._parent_pid = Noneself._popen = Noneself._closed = Falseself._sentinel = sentinelself._config = {}def is_alive(self):from multiprocessing.connection import waitreturn not wait([self._sentinel], timeout=0)@propertydef ident(self):return self._piddef join(self, timeout=None):'''Wait until parent process terminates'''from multiprocessing.connection import waitwait([self._sentinel], timeout=timeout)pid = ident## Create object representing the main process#class _MainProcess(BaseProcess):def __init__(self):self._identity = ()self._name = 'MainProcess'self._parent_pid = Noneself._popen = Noneself._closed = Falseself._config = {'authkey': AuthenticationString(os.urandom(32)),'semprefix': '/mp'}# Note that some versions of FreeBSD only allow named# semaphores to have names of up to 14 characters. Therefore# we choose a short prefix.## On MacOSX in a sandbox it may be necessary to use a# different prefix -- see #19478.## Everything in self._config will be inherited by descendant# processes.def close(self):pass_parent_process = None_current_process = _MainProcess()_process_counter = itertools.count(1)_children = set()del _MainProcess## Give names to some return codes#_exitcode_to_name = {}for name, signum in list(signal.__dict__.items()):if name[:3]=='SIG' and '_' not in name:_exitcode_to_name[-signum] = f'-{name}'# For debug and leak testing_dangling = WeakSet()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。