U
    2ÜŸj¤*  ã                   @  sØ   d Z ddlmZ ddlmZmZ ddlmZmZm	Z	m
Z
mZ ddlmZmZmZ ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ edƒZedƒZG dd„ deƒZG dd„ deƒZe ƒ Z!G dd„ dƒZ"dS )zº
twisted.python.threadpool: a pool of threads to which we dispatch tasks.

In most cases you can just use C{reactor.callInThread} and friends
instead of creating a thread pool directly.
é    )Úannotations)ÚThreadÚcurrent_thread)ÚAnyÚCallableÚListÚOptionalÚTypeVar)Ú	ParamSpecÚProtocolÚ	TypedDict)Úpool)ÚcontextÚlog)Ú
deprecated)ÚFailure)ÚVersionÚ_PÚ_Rc                   @  s   e Zd Zddœdd„ZdS )Ú_SupportsQsizeÚint©Úreturnc                 C  s   d S ©N© ©Úselfr   r   ú=/tmp/pip-unpacked-wheel-4b529toj/twisted/python/threadpool.pyÚqsize   s    z_SupportsQsize.qsizeN©Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   r      s   r   c                   @  s   e Zd ZU ded< ded< dS )Ú_Stater   ÚminÚmaxN)r    r!   r"   Ú__annotations__r   r   r   r   r#   "   s   
r#   c                   @  s^  e Zd ZdZdZdZdZdZdZe	Z
eeedddd	ƒd
d�eƒƒZeeƒZd?ddddœdd„Zeddœdd„ƒZeddœdd„ƒZeddœdd„ƒZeddœdd„ƒZeZddœdd„Zddœdd „Zd!dœd"d#„Zddœd$d%„Zd&dd'œd(d)„Zd&dœd*d+„Zd,d-d.dd/œd0d1„Zd2d3d-d.dd4œd5d6„Zddœd7d8„Z d@d9d9dd:œd;d<„Z!ddœd=d>„Z"dS )AÚ
ThreadPoolaè  
    This class (hopefully) generalizes the functionality of a pool of threads
    to which work can be dispatched.

    L{callInThread} and L{stop} should only be called from a single thread.

    @ivar started: Whether or not the thread pool is currently running.
    @type started: L{bool}

    @ivar threads: List of workers currently running in this thread pool.
    @type threads: L{list}

    @ivar _pool: A hook for testing.
    @type _pool: callable compatible with L{_pool}
    é   é   FNZTwistedé   é   r   zthreading.current_thread)ÚversionÚreplacementr   zOptional[str])Ú
minthreadsÚ
maxthreadsÚnamec                   sr   |dkst dƒ‚||ks t dƒ‚|ˆ _|ˆ _|ˆ _g ˆ _ddddœ‡ fdd„}d	d
œ‡ fdd„}ˆ  ||¡ˆ _dS )ac  
        Create a new threadpool.

        @param minthreads: minimum number of threads in the pool
        @type minthreads: L{int}

        @param maxthreads: maximum number of threads in the pool
        @type maxthreads: L{int}

        @param name: The name to give this threadpool; visible in log messages.
        @type name: native L{str}
        r   úminimum is negativeúminimum is greater than maximumr   r   )ÚaÚkwr   c                    s(   ˆ j | dˆ  ¡ i|—Ž}ˆ j |¡ |S )Nr0   )ÚthreadFactoryÚ_generateNameÚthreadsÚappend)r3   r4   Úthreadr   r   r   ÚtrackingThreadFactory`   s    ÿÿÿz2ThreadPool.__init__.<locals>.trackingThreadFactoryr   r   c                     s   ˆ j s
dS ˆ jS )Nr   )Ústartedr%   r   r   r   r   ÚcurrentLimitg   s    z)ThreadPool.__init__.<locals>.currentLimitN)ÚAssertionErrorr$   r%   r0   r7   Ú_poolÚ_team)r   r.   r/   r0   r:   r<   r   r   r   Ú__init__J   s    zThreadPool.__init__r   c                 C  s   | j  ¡ }|j|j S )a  
        For legacy compatibility purposes, return a total number of workers.

        @return: the current number of workers, both idle and busy (but not
            those that have been quit by L{ThreadPool.adjustPoolsize})
        @rtype: L{int}
        )r?   Ú
statisticsÚidleWorkerCountÚbusyWorkerCount)r   Ústatsr   r   r   Úworkersn   s    	
zThreadPool.workersz
list[None]c                 C  s   dg| j  ¡ j S )zý
        For legacy compatibility purposes, return the number of busy workers as
        expressed by a list the length of that number.

        @return: the number of workers currently processing a work item.
        @rtype: L{list} of L{None}
        N)r?   rA   rC   r   r   r   r   Úworkingz   s    	zThreadPool.workingc                 C  s   dg| j  ¡ j S )a,  
        For legacy compatibility purposes, return the number of idle workers as
        expressed by a list the length of that number.

        @return: the number of workers currently alive (with an allocated
            thread) but waiting for new work.
        @rtype: L{list} of L{None}
        N)r?   rA   rB   r   r   r   r   Úwaiters…   s    
zThreadPool.waitersr   c                   s   G ‡ fdd„dƒ}|ƒ S )zÙ
        For legacy compatibility purposes, return an object with a C{qsize}
        method that indicates the amount of work not yet allocated to a worker.

        @return: an object with a C{qsize} method.
        c                      s   e Zd Zddœ‡ fdd„ZdS )z$ThreadPool._queue.<locals>.NotAQueuer   r   c                   s   ˆ j  ¡ jS )a  
                Pretend to be a Python threading Queue and return the
                number of as-yet-unconsumed tasks.

                @return: the amount of backlogged work not yet dispatched to a
                    worker.
                @rtype: L{int}
                )r?   rA   ÚbackloggedWorkCount)Úqr   r   r   r   ›   s    	z*ThreadPool._queue.<locals>.NotAQueue.qsizeNr   r   r   r   r   Ú	NotAQueueš   s   rJ   r   )r   rJ   r   r   r   Ú_queue‘   s    	zThreadPool._queueÚNonec                 C  s4   d| _ d| _|  ¡  | j ¡ j}|r0| j |¡ dS )z'
        Start the threadpool.
        FTN)Újoinedr;   ÚadjustPoolsizer?   rA   rH   Úgrow)r   Úbacklogr   r   r   Ústart«   s    zThreadPool.startc                 C  s   | j  d¡ dS )zŒ
        Increase the number of available workers for the thread pool by 1, up
        to the maximum allowed by L{ThreadPool.max}.
        r+   N)r?   rO   r   r   r   r   ÚstartAWorker·   s    zThreadPool.startAWorkerÚstrc                 C  s   d| j pt| ƒ› d| j› �S )z‹
        Generate a name for a new pool thread.

        @return: A distinctive name for the thread.
        @rtype: native L{str}
        zPoolThread-ú-)r0   ÚidrE   r   r   r   r   r6   ¾   s    zThreadPool._generateNamec                 C  s   | j  d¡ dS )zn
        Decrease the number of available workers by 1, by quitting one as soon
        as it's idle.
        r+   N)r?   Úshrinkr   r   r   r   ÚstopAWorkerÇ   s    zThreadPool.stopAWorkerr#   )Ústater   c                 C  s"   t | d|ƒ t | | j| j¡ d S )NÚ__dict__)Úsetattrr'   r@   r$   r%   )r   rX   r   r   r   Ú__setstate__Î   s    zThreadPool.__setstate__c                 C  s   t | j| jd�S )N)r$   r%   )r#   r$   r%   r   r   r   r   Ú__getstate__Ò   s    zThreadPool.__getstate__zCallable[_P, object]z_P.argsz	_P.kwargs)ÚfuncÚargsr4   r   c                 O  s   | j d|f|ž|Ž dS )a   
        Call a callable object in a separate thread.

        @param func: callable object to be called in separate thread

        @param args: positional arguments to be passed to C{func}

        @param kw: keyword args to be passed to C{func}
        N)ÚcallInThreadWithCallback)r   r]   r^   r4   r   r   r   ÚcallInThreadÕ   s    zThreadPool.callInThreadz&Optional[Callable[[bool, _R], object]]zCallable[_P, _R])ÚonResultr]   r^   r4   r   c                   sV   | j r
dS tj ¡ jd ‰ddœ‡fdd„‰‡ ‡‡‡fdd„ˆ_|ˆ_| j ˆ¡ dS )	a$  
        Call a callable object in a separate thread and call C{onResult} with
        the return value, or a L{twisted.python.failure.Failure} if the
        callable raises an exception.

        The callable is allowed to block, but the C{onResult} function must not
        block and should perform as little work as possible.

        A typical action for C{onResult} for a threadpool used with a Twisted
        reactor would be to schedule a L{twisted.internet.defer.Deferred} to
        fire in the main reactor thread using C{.callFromThread}.  Note that
        C{onResult} is called inside the separate thread, not inside the
        reactor thread.

        @param onResult: a callable with the signature C{(success, result)}.
            If the callable returns normally, C{onResult} is called with
            C{(True, result)} where C{result} is the return value of the
            callable.  If the callable throws an exception, C{onResult} is
            called with C{(False, failure)}.

            Optionally, C{onResult} may be L{None}, in which case it is not
            called at all.

        @param func: callable object to be called in separate thread

        @param args: positional arguments to be passed to C{func}

        @param kw: keyword arguments to be passed to C{func}
        NéÿÿÿÿrL   r   c                    sf   zˆ   ¡ } d}W n tk
r.   tƒ } d}Y nX d ˆ _ ˆ jd k	rTˆ  || ¡ d ˆ _n|sbt | ¡ d S )NTF)ÚtheWorkÚBaseExceptionr   ra   r   Úerr)ÚresultÚok)Ú	inContextr   r   rh     s    

z6ThreadPool.callInThreadWithCallback.<locals>.inContextc                     s   t jˆˆfˆ žˆŽS r   )r   Úcallr   )r^   Úctxr]   r4   r   r   Ú<lambda>  s    ÿÿÿz5ThreadPool.callInThreadWithCallback.<locals>.<lambda>)	rM   r   ZtheContextTrackerZcurrentContextZcontextsrc   ra   r?   Zdo)r   ra   r]   r^   r4   r   )r^   rj   r]   rh   r4   r   r_   ã   s    $z#ThreadPool.callInThreadWithCallbackc                 C  s.   d| _ d| _| j ¡  | jD ]}| ¡  qdS )z9
        Shutdown the threads in the threadpool.
        TFN)rM   r;   r?   Úquitr7   Újoin)r   r9   r   r   r   Ústop$  s
    

zThreadPool.stopzOptional[int])r.   r/   r   c                 C  s–   |dkr| j }|dkr| j}|dks,tdƒ‚||ks<tdƒ‚|| _ || _| jsRdS | j| jkrr| j | j| j ¡ | j| j k r’| j | j | j ¡ dS )zî
        Adjust the number of available threads by setting C{min} and C{max} to
        new values.

        @param minthreads: The new value for L{ThreadPool.min}.

        @param maxthreads: The new value for L{ThreadPool.max}.
        Nr   r1   r2   )r$   r%   r=   r;   rE   r?   rV   rO   )r   r.   r/   r   r   r   rN   .  s    zThreadPool.adjustPoolsizec                 C  s:   t  d| j› �¡ t  d| j› �¡ t  d| j› �¡ dS )zw
        Dump some plain-text informational messages to the log about the state
        of this L{ThreadPool}.
        z	waiters: z	workers: ztotal: N)r   ÚmsgrG   rF   r7   r   r   r   r   Ú	dumpStatsM  s    zThreadPool.dumpStats)r(   r)   N)NN)#r    r!   r"   Ú__doc__r$   r%   rM   r;   r0   r   r5   Ústaticmethodr   r   r   ÚcurrentThreadr>   r@   ÚpropertyrE   rF   rG   rK   rI   rQ   rR   r6   rW   r[   r\   r`   r_   rn   rN   rp   r   r   r   r   r'   *   sT   þýÿ     ÿ$
	A   ÿr'   N)#rq   Ú
__future__r   Ú	threadingr   r   Útypingr   r   r   r   r	   Ztyping_extensionsr
   r   r   Ztwisted._threadsr   r>   Ztwisted.pythonr   r   Ztwisted.python.deprecater   Ztwisted.python.failurer   Ztwisted.python.versionsr   r   r   r   r#   ÚobjectZ
WorkerStopr'   r   r   r   r   Ú<module>   s   