#### 5.6.3.3线程池操作

线程池由多个线程组组成，每个线程组管理一组客户端连接。建立连接后，线程池会以循环方式将它们分配给线程组。

线程池公开可用于配置其操作的系统变量：

-   [`线程池算法`](server-system-variables.html#sysvar_thread_pool_algorithm)：用于调度的并发算法。

-   [`线程池高优先级连接`](server-system-variables.html#sysvar_thread_pool_high_priority_connection)：如何安排会话的语句执行。

-   [`线程\u池\u最大\u活动\u查询\u线程`](server-system-variables.html#sysvar_thread_pool_max_active_query_threads)：每个组允许多少活动线程。

-   [`线程\u池\u最大\u未使用的\u线程`](server-system-variables.html#sysvar_thread_pool_max_unused_threads)：允许多少睡眠线程。

-   [`线程\u池\u优先级\u启动\u计时器`](server-system-variables.html#sysvar_thread_pool_prio_kickup_timer)：线程池将等待执行的语句从低优先级队列移动到高优先级队列之前的时间。

-   [`线程池大小`](server-system-variables.html#sysvar_thread_pool_size)：线程池中的线程组数。这是控制线程池性能的最重要参数。

-   [`线程池暂停限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)：执行语句被认为暂停之前的时间。

    要配置线程组的数量，请使用[`线程池大小`](server-system-variables.html#sysvar_thread_pool_size)系统变量。默认组数为16。有关设置此变量的指导原则，请参阅[第5.6.3.4节，“线程池调优”](thread-pool-tuning.html).

    每个组的最大线程数为4096（在某些内部使用一个线程的系统上为4095）。

    线程池将连接和线程分开，因此连接和执行从这些连接接收的语句的线程之间没有固定的关系。这与默认的线程处理模型不同，默认的线程处理模型将一个线程与一个连接相关联，以便给定的线程从其连接执行所有语句。

    默认情况下，线程池尝试确保每个组在任何时候最多执行一个线程，但有时允许临时执行更多线程以获得最佳性能：

-   每个线程组都有一个侦听器线程，用于侦听来自分配给该组的连接的传入语句。当一条语句到达时，线程组要么立即开始执行它，要么将其排队等待以后执行：

    -   如果该语句是唯一接收到的语句，并且没有任何语句排队或当前正在执行，则会立即执行。

    -   如果语句不能立即开始执行，则会发生排队。

-   如果立即执行，侦听器线程将执行它。（这意味着组中暂时没有线程在侦听。）如果语句快速完成，则执行线程返回侦听语句。否则，线程池会将语句视为已暂停，并将另一个线程作为侦听器线程启动（如果需要，创建它）。为了确保没有线程组被停滞的语句阻塞，线程池有一个后台线程，它定期监视线程组状态。

    通过使用侦听线程执行一个可以立即开始的语句，如果语句快速完成，则无需创建额外线程。这确保了在并发线程数量较少的情况下，执行效率最高的可能性。

    当线程池插件启动时，它会创建每个组（侦听器线程）一个线程，以及后台线程。在执行语句时，将根据需要创建其他线程。

-   的值[`线程\u池\u失速\u限制`](server-system-variables.html#sysvar_thread_pool_stall_limit)系统变量确定前一项中“快速完成”的含义。线程被认为已停止的默认时间为60ms，但最多可设置为6s。此参数可配置为使您能够达到适合服务器工作负载的平衡。短等待值允许线程更快地启动。短值也更适合避免死锁情况。长等待值对于包含长时间运行语句的工作负载非常有用，以避免在当前语句执行时启动太多新语句。

-   如果[`线程\u池\u max\u活动\u查询\u线程`](server-system-variables.html#sysvar_thread_pool_max_active_query_threads)默认算法适用于确定每个组的最大活动线程数。默认算法考虑了已暂停的线程，并可能暂时允许更多活动线程。如果[`线程\u池\u max\u活动\u查询\u线程`](server-system-variables.html#sysvar_thread_pool_max_active_query_threads)大于0，它对每个组的活动线程数设置限制。

-   线程池的重点是限制并发短运行语句的数量。在执行语句到达暂停时间之前，它阻止其他语句开始执行。如果语句在失速时间后执行，则允许继续，但不再阻止其他语句启动。这样，线程池会尝试确保在每个线程组中不会有多个短运行语句，尽管可能存在多个长运行语句。不希望让长时间运行的语句阻止其他语句执行，因为等待的数量没有限制，这可能是必要的。例如，在复制源服务器上，将二进制日志事件发送到副本的线程将永远有效运行。

-   如果语句遇到磁盘I/O操作或用户级锁（行锁或表锁），则该语句将被阻止。该块将导致线程组变得不使用，因此对线程池进行回调，以确保线程池可以立即启动该组中的新线程以执行另一个语句。当阻塞的线程返回时，线程池允许它立即重新启动。

-   有两个队列，一个高优先级队列和一个低优先级队列。事务中的第一条语句进入低优先级队列。如果事务正在进行（事务的语句已开始执行），则事务的任何以下语句都将进入高优先级队列，否则将进入低优先级队列。启用[`线程池高优先级连接`](server-system-variables.html#sysvar_thread_pool_high_priority_connection)系统变量，使会话的所有排队语句进入高优先级队列。

    非事务性存储引擎或事务性引擎（如果有）的语句[`自动提交`](server-system-variables.html#sysvar_autocommit)已启用，则被视为低优先级语句，因为在这种情况下，每条语句都是一个事务。因此，对于`InnoDB`和`米萨姆`表中，线程池会为`InnoDB`在那些上面`米萨姆`除非[`自动提交`](server-system-variables.html#sysvar_autocommit)已启用。具有[`自动提交`](server-system-variables.html#sysvar_autocommit)启用时，所有语句的优先级都较低。

-   当线程组选择要执行的排队语句时，它首先查看高优先级队列，然后查看低优先级队列。如果找到一条语句，它将从队列中删除并开始执行。

-   如果语句在低优先级队列中停留的时间过长，线程池将移至高优先级队列。价值[`线程\u池\u优先级\u启动\u计时器`](server-system-variables.html#sysvar_thread_pool_prio_kickup_timer)系统变量控制移动前的时间。对于每个线程组，每10ms（每秒100次）最多有一条语句从低优先级队列移动到高优先级队列。

-   线程池重用最活跃的线程，以更好地利用CPU缓存。这是一个对性能有很大影响的小调整。

-   当线程从用户连接执行语句时，Performance Schema instrumentation会将线程活动记录到用户连接。否则，性能模式会将活动记录到线程池中。

    以下是线程组可能有多个线程开始执行语句的条件示例：

-   一个线程开始执行一条语句，但运行的时间足够长，因此被认为已暂停。线程组允许另一个线程开始执行另一条语句，即使第一个线程仍在执行。

-   一个线程开始执行一条语句，然后被阻塞并将其报告回线程池。线程组允许另一个线程开始执行另一条语句。

-   一个线程开始执行一条语句，被阻塞，但不会报告它被阻塞，因为该阻塞不会出现在已使用线程池回调检测的代码中。在这种情况下，线程组认为线程仍在运行。如果该块持续的时间足以使该语句被认为已暂停，则该组允许另一个线程开始执行另一条语句。

    线程池被设计成可以跨越来越多的连接进行扩展。它还旨在避免由于限制活动执行语句的数量而导致的死锁。重要的是，不向线程池报告的线程不会阻止其他语句执行，从而导致线程池死锁。这类声明的例子如下：

-   长时间的陈述。这将导致所有资源仅由少数语句使用，并且可能会阻止所有其他语句访问服务器。

-   二进制日志转储线程，读取二进制日志并将其发送到副本。这是一种长时间运行的“语句”，运行时间很长，不应阻止其他语句执行。

-   语句在行锁、表锁、睡眠或任何其他阻止活动上被阻止，而MySQL服务器或存储引擎尚未将这些阻止活动报告回线程池。

    在每种情况下，为了防止死锁，当语句不能很快完成时，会将语句移动到stalled类别，这样线程组就可以允许另一条语句开始执行。在这种设计中，当一个线程执行或被阻塞很长时间时，线程池会将该线程移动到暂停类别，在语句执行的其余部分，它不会阻止其他语句执行。

    可以出现的最大线程数是[`max_连接`](server-system-variables.html#sysvar_max_connections)和[`线程池大小`](server-system-variables.html#sysvar_thread_pool_size)。如果所有连接都处于执行模式，并且每个组都会创建一个额外线程来侦听更多语句，则可能会发生这种情况。这种情况不一定经常发生，但理论上是可能的。
