WIN内核线程池函数

线程池

(本章节中例子都是用 VS2010 编译调试的)

线程池编写必须在 Windows Vista 操作系统(以及以上版本的操作系统)下,且
C++ 编译器版本至少是 VS2008

线程池的功能

  • 以异步的方式来调用一个函数
  • 每隔一段时间调用一个函数
  • 当内核对象触发的时候调用一个函数
  • 当异步 I/O 请求完成的时候调用一个函数

注意

当一个进程初始化的时候,它并没有任何与线程池的开销.但是,一旦调用了新的线程池函数,系统就会为进程相应的内核资源,其中的一些资源在进程终止之前都将一直存在.正如我们可以看到,使用线程池的开销取决于用法:系统会以进程的名义来分配线程,其他内核以及内部数据结构.因此我们不应该盲目地使用这些线程池函数,而是必须谨慎地考虑,这些函数能做什么,以及它们不能做什么.

在线程池编程中,我们从来不需要自己调用 CreateThread.系统会自动为我们的进程创建线程,并在规定的条件下让线程池中的线程调用我们的回调函数.此外,这个线程在处理完成一个客户请求后,它不会立刻被销毁,而是回到线程池,准备好处理队列中的任何其他工作项,线程池会不断地重复使用其中的线程,而不会频繁地创建销毁线程,对应用程序来说,这样可以显著地提升性能,因为创建和销毁线程会消耗大量的时间.当然,如果线程池检测到创建的另一个线程将能更好地为应用程序服务,那么它会这样做.如果线程池检测到它的线程数量已经供过于求,那么它会销毁其中一些线程.除非我们非常清楚自己在做什么,否则的话最好还是相信线程内部的算法,让它自动地对应用程序的工作量进行微调.

默认线程池,在进程存在期间它不会被销毁.生命周期与进程相同.在进程终止的时候,Windows 会将其销毁并负责所有的清理工作.

对线程池的制定

可以用 CreateThreadpool 来创建一个新的线程池,该函数返回一个
PTP_POOL 值,表示新创建的线程池.接着我们可以调用后面两个函数来设置线程池中线程的最大数量和最小数量 SetThreadpoolThreadMinimum / SetThreadpoolThreadMaximum 线程池始终保持池中的线程数量至少是指定的最小数量,并允许线程数量增长到指定的最大数量,顺便一提,默认线程池的最小数量为1,最大数量为500.然后在引用程序不在需要自定义线程池时,应调用 CloseThreadpool 将其销毁.在调用这个函数后,我们将无法在将任何新的项添加到线程池的队列中.线程池中当前正在处理的队列中的线程会完成它们的处理并终止.此外,线程池的队列中所有尚未开始处理的项将被取消.

一旦我们创建了自己的线程池,并制定了线程池的最小数量和最大数量,我们就可以初始化一个回调环境,它包含了一些课应用于工作项的额外的设置或配置.(线程池回调环境结构 _TP_CALLBACK_ENVIRON ,其定义在 WinNT.h )

/***************************************
显示此结果的编译环境为 VS2010
***************************************/
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)

typedef struct _TP_CALLBACK_ENVIRON_V3 {
    TP_VERSION                         Version;
    PTP_POOL                           Pool;
    PTP_CLEANUP_GROUP                  CleanupGroup;
    PTP_CLEANUP_GROUP_CANCEL_CALLBACK  CleanupGroupCancelCallback;
    PVOID                              RaceDll;
    struct _ACTIVATION_CONTEXT        *ActivationContext;
    PTP_SIMPLE_CALLBACK                FinalizationCallback;
    union {
        DWORD                          Flags;
        struct {
            DWORD                      LongFunction :  1;
            DWORD                      Persistent   :  1;
            DWORD                      Private      : 30;
        } s;
    } u;
    TP_CALLBACK_PRIORITY               CallbackPriority;
    DWORD                              Size;
} TP_CALLBACK_ENVIRON_V3;

typedef TP_CALLBACK_ENVIRON_V3 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;

#else

typedef struct _TP_CALLBACK_ENVIRON_V1 {
    TP_VERSION                         Version;
    PTP_POOL                           Pool;
    PTP_CLEANUP_GROUP                  CleanupGroup;
    PTP_CLEANUP_GROUP_CANCEL_CALLBACK  CleanupGroupCancelCallback;
    PVOID                              RaceDll;
    struct _ACTIVATION_CONTEXT        *ActivationContext;
    PTP_SIMPLE_CALLBACK                FinalizationCallback;
    union {
        DWORD                          Flags;
        struct {
            DWORD                      LongFunction :  1;
            DWORD                      Persistent   :  1;
            DWORD                      Private      : 30;
        } s;
    } u;
} TP_CALLBACK_ENVIRON_V1;

typedef TP_CALLBACK_ENVIRON_V1 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;

#endif

然后我们可以调用 InitializeThreadpoolEnvironment 初始化这个结构体,接着当然回调环境必须调用 SetThreadpoolCallbackPool 标明给工作项应该由哪个线程池来处理.最后当我们不在需要这个使用线程池回调环境的时候,应该调用 DestroyThreadpoolEnvironment 来对它进行清理工作.

    • 然而可以调用 SetThreadpoolCallbackRunsLong 函数来告诉回调环境,工作项通常需要较长的时间来处理.这使得线程池会更快地创建线程,其目的是为了尝试在对工作项进行处理的时候,以一种更为公平的方式来替代最有效的方式.
    • 也可以调用 SetThreadpoolCallbackLibrary 来确保只要线程池中还有待处理的工作项,就将一个特定的
      DLL 一直保持在进程空间中.基本上 SetThreadpoolCallbackLibrary 函数的存在目的是为了消除潜在的竞态条件(race
      condition),从而避免可能导致死锁.这个相当高级的特性,更详细信息参阅 Platform SDK 文档.

线程池的销毁(清理组)

为了得体地销毁私有线程池,我们首先可以需要通过调用 CreateThreadpoolCleanupGroup 来创建一个清理组,然后再将这个清理组与一个以绑定到线程池的回调函数结构体
TP_CALLBACK_ENVIRON 调用 SetThreadpoolCallbackCleanupGroup 函数把两者关联起来.其中 SetThreadpoolCallbackCleanupGroup 的
pfng 参数标识一个回调函数的地址(函数原型 即CleanupGroupCancelCallback),如果传给
pfng 参数值不为 NULL ,且当清理组被取消时那么这个回调函数会被调用.

当我们调用 CreateThreadpoolWorkCreateThreadpoolTimerCreateThreadpoolWait 或 CreateThreadpoolIo 的时候,如果最后那个参数,即指向
PTP_CALLBACK_ENVIRON 结构体指针,不等于 NULL,那么所创建的项会被添加到对应的回调环境的清理组中,其目的是为了表示有线程池中添加了一项,需要潜在清理.在这些对了项完成后,如果我们调用 CloseThreadpoolWorkCloseThreadpoolTimerCloseThreadpoolWait 和 CloseThreadpoolIo,
那就等于是隐式将对应的项从组中移除.

最后,在程序想要销毁线程池的时候,调用 CloseThreadpoolCleanupGroupMembers.这个函数与下面的
WaitForThreadpool*(例: WaitForThreadpoolWork)函数相似.当线程调用 CloseThreadpoolCleanupGroupMembers 时候,函数会一直等待,知道线程池的工作组中所有剩余的项(即已经创建当尚未关闭的项)都已经处理完毕为止.调用者还可以传
TRUE 给 fCancelPendingCallbacks  参数.这样会将所有已提交但尚未处理的工作项直接取消,函数会在所有当前正在运行的工作项王城之后返回.如果传给 fCancelPendingCallbacks 参数为 TRUE,而且传给 SetThreadpoolCallbackCleanupGroup 的
pfng 参数值是一个 CleanupGroupCancelCallback 函数地址,那么对每一个被取消的工作项,我们的回调函数会被调用,在 CleanupGroupCancelCallback 函数中.参数
ObjectContext 会包含每个被取消的上下文.(该上下文信息是通过 CreateThreadpool* 函数的 pv 参数设置的)在 CleanupGroupCancelCallback 函数中,
参数 CleanupContext 包含的上下文是通过 CloseThreadpoolCleanupGroupMembers 函数的 pvCleanupContext
参数传入的.如果在调用 CloseThreadpoolCleanupGroupMembers 时传入
FALSE 给 fCancelPendingCallbacks 参数.那么在返回之前,线程池会发时间来处理队列中所有剩余的项.注意这种情况下我们的 CleanupGroupCancelCallback 函数绝对不会被调用.因此可以传
NULL 给 pvCleanupContext 参数.

线程池制定与销毁代码样例

编写步骤

程序源码

#include<Windows.h>
#include<iostream>
#include<cstdlib>

using namespace std;

VOID CALLBACK SimpleCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context);

void main()
{
    PTP_POOL tPool;
    TP_CALLBACK_ENVIRON pcbe;

    //创建线程池
    tPool = CreateThreadpool(NULL);

    //设置线程池最大最小的线程数量
    SetThreadpoolThreadMinimum(tPool,1);
    SetThreadpoolThreadMaximum(tPool,2);

    //初始化线程池环境变量
    InitializeThreadpoolEnvironment(&pcbe);

    //为线程池设置线程池环境变量
    SetThreadpoolCallbackPool(&pcbe,tPool);

    //单次工作提交
    TrySubmitThreadpoolCallback(SimpleCallback,NULL,&pcbe);

    system("pause");
    //清理线程池的环境变量
    DestroyThreadpoolEnvironment(&pcbe);
    //关闭线程池
    CloseThreadpool(tPool);
}

VOID CALLBACK SimpleCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context)
{
    cout<<"this is SimpleCallback function!"<<endl;
}

运行结果

以异步的方式调用函数

相关函数

  • TrySubmitThreadpoolCallback (向线程池提交工作请求函数<一次性>,回调函数原型)
  • CreateThreadpoolWork (为线程池创建一个提交工作的工作对象,回调函数原型)

    绝对不要让回调函数调用 WaitForThreadpoolWork 并将自己的工作项作为参数传入,因为这样会导致死锁.

  • SubmitThreadpoolWork (想线程池提交工作请求函数<非一次性>)
  • WaitForThreadpoolWorkCallbacks (取消已提交但未执行的工作项
    / 等待工作项处理完成把自己挂起)

    其中的 fCancelPendingCallbacks 参数

      若为 true ,函数会试图取消先前提交的那个工作项.如果线程池中的线程正在处理那个工作项,那么该过程不会被打断,函数会一直等到该工作项已经被处理完成后在返回.

      若为 false ,那么函数会将调用线程挂起,知道指定工作项的处理已经完成而且线程池中处理该工作项的线程也已经被回收并准备处理下一个工作项.

    如果用一个 PTP_WORK 对象已经提交了很多工作项,而且传给 fCancelPendingCallbacks 参数为 false,那么 WaitForThreadpoolWorkCallbacks 会等待线程池处理完所有提交的工作项.如果传给 fCancelPendingCallbacks 为 true,那么 WaitForThreadpoolWorkCallbacks 只会等到当前正在运行的工作项完成为止.

  • CloseThreadpoolWork (取消可以多次提交工作的工作对象)

编写步骤

代码样例

程序源码

#include<Windows.h>
#include<iostream>
#include<cstdlib>

using namespace std;

VOID CALLBACK SimpleCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context);
VOID CALLBACK WorkCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WORK Work);

void main()
{
    PTP_WORK tpWork;

    //单次工作提交
    TrySubmitThreadpoolCallback(SimpleCallback,NULL,NULL);

    //创建工作对象
    tpWork = CreateThreadpoolWork(WorkCallback,NULL,NULL);

    //提交工作
    SubmitThreadpoolWork(tpWork);
    SubmitThreadpoolWork(tpWork);

    //等待工作结束
    WaitForThreadpoolWorkCallbacks(tpWork,false);
    //关闭工作对象
    CloseThreadpoolWork(tpWork);

    system("pause");
}

VOID CALLBACK SimpleCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context)
{
    cout<<"this is SimpleCallback function!"<<endl;
}

VOID CALLBACK WorkCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WORK Work)
{
    cout<<"this is WorkCallback function!"<<endl;
}

运行结果

以时间段来调用函数

相关函数

编写步骤

代码样例

程序源码

#include<Windows.h>
#include<iostream>
#include<cstdlib>

using namespace std;

VOID CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_TIMER Timer);

void main()
{
    PTP_TIMER tpTimer;
    FILETIME liDueTime;
    LARGE_INTEGER liUTC;

    liUTC.QuadPart = -30000000;

    liDueTime.dwLowDateTime = liUTC.LowPart;
    liDueTime.dwHighDateTime = liUTC.HighPart;

    //创建定时调用的工作对象
    tpTimer = CreateThreadpoolTimer(TimerCallback,NULL,NULL);

    //判断定时调用的工作对象是否注册过计时器
    if(!IsThreadpoolTimerSet(tpTimer))
    {
        //为定时调用工作对象注册计时器
        SetThreadpoolTimer(tpTimer,&liDueTime,0,0);
    }

    //睡眠主进程,等待计时器添加工作
    Sleep(4000);

    //等待定时调用的工作对象
    WaitForThreadpoolTimerCallbacks(tpTimer,false);

    //关闭定时调用的工作对象
    CloseThreadpoolTimer(tpTimer);

    system("pause");
}

VOID CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_TIMER Timer)
{
    cout<<"this is TimerCallback function!"<<endl;
}

运行结果

以内核对象的触发状态来调用函数

运行原理

其实,在此功能中线程池在内部会让一个线程调用 WaitForMultipleObjects 函数,传入通过 SetThreadpoolWait 函数注册一组句柄,并传入
false 给 bWaitAll 参数,这样当任何一个句柄被触发的时候,线程池就会被唤醒.由于 WaitForMultipleObjects 有一个限制,一次嘴甜只能等待
64(MAXMUM_WAIT_OBJECTS)个句柄,因此线程池事实上正是为每 64 个内核对象分配一个线程来进行等待,其效率还是相当高的.另外,由于 WaitForMultipleObjects 不允许我们将同一个句柄传入多次,因此我们必须确保不会用 SetThreadpoolWait 来多次注册同一个句柄.但是,我们可以调用 DuplicateHandle,
这样就可以分别注册原始句柄和复制句柄.

注意

绝对不要让回调函数调用 WaitForThreadpoolWait 并将自己的工作项作为参数传入,因为这样会导致死锁.另外,当线程在等待传给 SetThreadpoolWait 的句柄时,我们应该确保该句柄不会被关闭.最后我们可能并不想通过 PulseEvent 来触发一个已注册的事件,因为当 PulseEvent 被调用的时候,我们无法保证线程池正好在等待该事件.

相关函数

  • CreateThreadpoolWait (为线程池创建一个等待内核对象触发的工作对象,回调函数原型)
  • SetThreadpoolWait (将内核绑定到等待内核对象触发的工作对象上)

    如果想让回调函数在同一个内核对象被触发的时候再次被调用,那么需要调用 SetThreadpoolWait 来再次注册.也可以通过 SetThreadpoolWait 来重用该等待项,即可以传入一个不同的内核对象句柄,也可以传入 NULL 来将该等待项从线程池中移除

  • WaitForThreadpoolWaitCallbacks (取消已提交但未执行的等待内核对象触发的工作项
    / 等待现有等待内核对象触发的工作项处理完成把自己挂起)
  • CloseThreadpoolWait (取消等待内核对象触发的工作对象)

编写步骤

代码样例

程序源码

#include<Windows.h>
#include<iostream>
#include<cstdlib>

using namespace std;

VOID CALLBACK WaitCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WAIT Wait,TP_WAIT_RESULT WaitResult);

void main()
{
    PTP_WAIT tpWait;
    HANDLE hMutex;

    //创建等待内核对象触发的工作对象
    tpWait = CreateThreadpoolWait(WaitCallback,NULL,NULL);
    //创建互斥对象
    hMutex=CreateMutex(NULL,false,0);

    //等待互斥对象被释放后获得互斥对象拥有权
    WaitForSingleObject(hMutex,INFINITE);

    //设置等待内核事件触发调用回调函数
    SetThreadpoolWait(tpWait,hMutex,0);

    //释放互斥对象拥有权
    ReleaseMutex(hMutex);

    //等待等待内核对象触发的工作对象结束
    WaitForThreadpoolWaitCallbacks(tpWait,false);
    //关闭等待内核对象触发的工作对象
    CloseThreadpoolWait(tpWait);

    system("pause");
}

VOID CALLBACK WaitCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WAIT Wait,TP_WAIT_RESULT WaitResult)
{
    cout<<"this is WaitCallback function!"<<endl;
}

运行结果

以异步 I/O 请求完成时调用函数

相关函数

  • CreateThreadpoolIo (为线程池创建一个异步
    I/O 请求完成的工作对象,回调函数原型)
  • StartThreadpoolIo (将嵌入在
    I/O 项中的文件/设备与线程池内部的 I/O 完成端口关联起来)

    在每次调用 ReadFile 和 WriteFile 之前,我们必须调用 StartThreadpoolIo.如果每次在发出 I/O 请求之前没有调用 StartThreadpoolIo,那么 IoCompletionCallback 回调函数将不会被回调

  • CancelThreadpoolIo (在发出
    I/O 请求之后让线程池停止调用回调函数)
  • WaitForThreadpoolIoCallbacks (取消已提交但未执行的异步
    I/O 请求完成的工作项 / 等待异步 I/O 请求完成的工作项处理完成把自己挂起)
  • CloseThreadpoolIo (取消异步
    I/O 请求完成的工作对象)

代码样例

  1. HANDLE hFile = CreateFileW(L"d:\\test.txt", GENERIC_ALL, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);//打开一个设备
  2. PTP_IO pio = CreateThreadpoolIo(hFile, OverlappedCompletionRoutine, NULL, NULL);//将设备对象和线程池的IO完成端口关联起来。
  3. DWORD err = GetLastError();
  4. MyOverlapped ol;//使用一个自定义的OVERLAPPED
  5. ol.Offset = 4;
  6. StartThreadpoolIo(pio);//每次发起一个异步io请求的时候,都要调一下这个函数,不然在CloseThreadpoolIo()的时候会出异常。
  7. BOOL rt = ReadFile(hFile, ol.GetByte(), 4, NULL, &ol);//发起一个异步IO
  8. MyOverlapped ol2;
  9. ol2.Offset = 5;
  10. StartThreadpoolIo(pio);
  11. rt = ReadFile(hFile, ol2.GetByte(), 5, NULL, &ol2);//再发起一个异步IO
  12. Sleep(4000);
  13. CloseHandle(hFile);//关闭文件对象
  14. CloseThreadpoolIo(pio);//关闭线程池io完成对象

对回调函数的操作

回调函数的终止操作

线程池提供了一种便利的方法,用来描述在我们的回调函数返回之后,应该执行的一些操作,回调函数用传给它的不透明的 Instance 参数(其类型为 PTP_CALLBACK_INSTANCE)来调用下面的函数

另外两个函数

  • CallbackMayRunLong

    此函数用来通知线程池回调函数的运行时间会比较长.如果一个回调函数认为自己需要较长的时间来处理当前的项,那么它应该调用 CallbackMayRunLong.由于线程池会坚持不创建新线程,因为长时间运行的项可能会使线程池队列中的其他项挨饿.如果 CallbackMayRunLong 返回 TRUE,那么说明线程池中还有其他线程可供使用,来对队列中的项进行处理.如果
    CallbackMayRunLong 返回 false,那么说明线程池中没有其他线程可以用来处理队列中的项.为了维持线程池的运行效率,最好是让该项将它的任务划分成更小的步伐来处理(将每一个部分单独地添加到线程池的队列中).任务的第一部分可以当前线程中执行.

  • DisassociateCurrentThreadFromCallback

    回调函数调用它来告诉线程池,逻辑上自己已经完成了工作,这使得任何由于调用 WaitForThreadpoolWorkCallbacks, WaitForThreadpoolTimerCallbacks, WaitForThreadpoolWaitCallbacks 或 WaitForThreadpoolIoCallbacks
    而被阻塞的线程能够早一些返回,而不必等到线程池的线程从回调函数中返回

时间: 2024-10-07 21:33:47

WIN内核线程池函数的相关文章

windows线程池四种情形(win核心读书笔记)

windows线程池四种情形(win核心读书笔记) Mircosoft从Windows2000引入线程池API,并在Vista后对线程池重新构架,引入新的线程池API.以下所有线程池函数均适用于Vista以后的版本. 用Windows提供的线程池函数有以下几个好处:1,不必要用CreateThread创建线程:2,不必要管理自己线程:3,Windows封装好的线程池,效率高,性能优越. 1 异步方式调用函数 这种方式和我们用CreateThread创建线程的用法差不多,给定一个线程函数模板实现功

线程池(VC_Win32)

线程池 (本章节中例子都是用 VS2010 编译调试的) 线程池编写必须在 Windows Vista 操作系统(以及以上版本的操作系统)下,且 C++ 编译器版本至少是 VS2008 线程池的功能 以异步的方式来调用一个函数 每隔一段时间调用一个函数 当内核对象触发的时候调用一个函数 当异步 I/O 请求完成的时候调用一个函数 注意 当一个进程初始化的时候,它并没有任何与线程池的开销.但是,一旦调用了新的线程池函数,系统就会为进程相应的内核资源,其中的一些资源在进程终止之前都将一直存在.正如我

linux内核线程的创建与销毁

linux将创建内核线程的工作交给了一个专门的内核线程kthreadd来完成,该线程会检查全局链表kthread_create_list,如果为NULL,就会调schedule()放弃cpu进入睡眠状态,否则就取下该链表中的一项创建对应的线程.本文就从khtreadd内核线程的创建开始来展示一下内核线程的创建过程.1 kthreaddlinux2.6.30,创建内核线程是通过kethradd内核守护线程来完成的,虽然机制上有所变化,但是最终还是调用do_fork来完成线程的创建.Kthreadd

linux线程池分析

一. 线程池学习文件 pool_test/  -> 线程池函数接口实现源码,简单实例. 系统编程项目接口设计说明书.doc  -> 详细说明了线程池各个函数的头文件/原型/参数/返回值... 线程池模型.jpg  -> 帮助大家理解线程池原理. 二. 学习线程池实现过程? 1. 什么是线程池? 线程池就是多个线程组合起来的一个集合,当有任务时,线程就会处理任务,当没有任务时,线程休息. 2. 分析线程池源码 thread_pool.c  -> 线程池函数接口源码 thread_po

经典的线程池--用户空间与内核空间实现的对比

经典的线程池模型是一组线程抢一个资源链表的模型,程序启动了一组线程,让它们等待信号waitQ的到来.同时又初始化一个资源链表,当某个线程往资源链表中添加一个资源时,它同时使用信号通知线程池.线程池中的线程接到信号后,就从资源链表中取出资源进行处理. 接下来,我们先来观察一下用户空间线程池的创建过程吧! 1 int 2 init (xlator_t *this) 3 { 4 iot_conf_t *conf = NULL; 5 int ret = -1; 6 int i = 0; 7 8 if (

c#网络通信框架networkcomms内核解析之十 支持优先级的自定义线程池

本例基于networkcomms2.3.1开源版本  gplv3协议 如果networkcomms是一顶皇冠,那么CommsThreadPool(自定义线程池)就是皇冠上的明珠了,这样说应该不夸张的,她那么优美,简洁,高效. 在 <c#网络通信框架networkcomms内核解析之六 处理接收到的二进制数据>中我们曾经提到,服务器收到数据后,如果是系统内部保留类型数据或者是最高优先级数据,系统会在主线程中处理,其他的会交给自定义线程池进行处理. 作为服务器,处理成千上万的连接及数据,单线程性能

进程池、线程池及回调函数使用

一.线程池与进程池 池表示容器 线程就是装线程的容器 为什么要装到容器中 可以避免频繁的创建和销毁(进程/线程)来的资源开销 可以限制同时存在的线程数量 以保证服务器不会应为资源不足而导致崩溃 帮我们管理了线程的生命周期 管理了任务的分配 import os import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import activeCount,enum

C#多线程实现方法——线程池(Thread Pool)

ThreadPool使用 同步机制 ThreadPool使用 需要定义waitcallback委托形式如 [csharp] view plain copy print? public delegate void WaitCallback(object state); public delegate void WaitCallback(object state); 例如如下例子: [csharp] view plain copy print? static private void ThreadW

Mysql线程池优化笔记

Mysql线程池优化我是总结了一个站长的3篇文章了,这里我整理到一起来本文章就分为三个优化段了,下面一起来看看. Mysql线程池系列一(Thread pool FAQ) 首先介绍什么是mysql thread pool,干什么用的?使用线程池主要可以达到以下两个目的:1.在大并发的时候,性能不会因为过载而迅速下降.2.减少性能抖动 thread pool的工作原理?线程池使用分而治之的方法来限制和平衡并发性.与默认的thread_handling不同,线程池将连接和线程划分开,所以连接数量和执