Work Control - ZjzMisaka/PowerThreadPool.zh-CN.Wiki GitHub Wiki

快速开始

摘要

Pause(...)
暂停线程池或任务, 可以使用 work id(s) 作为参数.
Resume(...)
恢复线程池或任务, 可以使用 work id(s) 作为参数.
Stop(...)
停止线程池或任务, 可以使用 work id(s)强制停止标志 作为参数.
Wait[Async](...)
阻塞并等待线程池或任务完成, 可以使用 work id(s) 作为参数.
Fetch[Async](...)
阻塞并获取任务结果, 可以使用 work id(s)谓词函数 以及 获取后从存储中移除结果标志 作为参数.
Cancel(...)
取消尚未开始的任务, 可以使用 work id(s) 作为参数.
PauseIfRequested()
在任务逻辑中插入一个暂停点.
StopIfRequested(...)
在任务逻辑中插入一个停止点, 可以使用 在停止过程前执行的函数 作为参数.
CheckIfRequestedStop()
在任务逻辑中插入一个检查点, 查看是否通过调用 Stop(...) 请求了停止.

示例代码

PowerPool powerPool = new PowerPool();

string id0 = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        if (powerPool.CheckIfRequestedStop())
        {
            return true;
        }
        // Do something
    }
});
Task<ExecuteResult<bool>> resultTask = powerPool.FetchAsync<bool>(id0);
powerPool.Pause();
powerPool.Resume();
powerPool.Stop();
powerPool.Wait();
ExecuteResult<bool> result = await resultTask;

string id1 = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        powerPool.StopIfRequested();
        // Do something
    }
});
powerPool.Pause(id1);
powerPool.Resume(id1);
powerPool.Stop(id1);
powerPool.Wait(id1);

详细说明

Pause(暂停) Resume(恢复) Stop(停止)

由于 Thread.Abort, Thread.SuspendThread.Resume 可能导致不可预测的行为, 它们在较新的 .NET 版本中已被弃用, 因此 PowerThreadPool 库也不使用这些 API 来控制线程.
PowerThreadPool 封装了 CancellationTokenSourceManualResetEvent 的操作, 提供了协作式的线程池和任务控制.

协作控制

可以在任务逻辑中插入 PauseIfRequested(), StopIfRequested(...)CheckIfRequestedStop() (例如在循环或耗时逻辑的节点中), 以管理执行流程. 当调用 Pause, Resume 或 Stop 函数时, 逻辑将在预期位置暂停, 恢复或停止. 使用任务 ID 作为这些函数的参数可以确保其他任务不受影响.

  • PauseIfRequested():在任务逻辑中调用此函数, 当用户调用 Pause(...) 时, 任务将在此处暂停.
  • StopIfRequested(Func<bool> beforeStop = null):在任务逻辑中调用此函数, 当用户调用 Stop(...) 时, 任务将在此处停止.
    为了退出逻辑, 该函数将抛出 PowerThreadPool.Exceptions.WorkStopException. WorkStopException 仅用于停止任务, 不要捕获它, 因为 PowerThreadPool 会处理它.
    如果你希望在停止之前执行某些操作 (例如释放一些非托管资源)或在某些情况下阻止停止, 建议使用参数 beforeStop.
    如果不希望以这种方式退出逻辑, 也可以使用 CheckIfRequestedStop.
  • CheckIfRequestedStop():在任务逻辑中调用此函数, 以检查是否已请求停止 (如果用户调用了 Stop(...)).
    当返回 true 时, 你可以执行一些预处理操作 (如释放非托管资源), 然后安全地退出逻辑. 根据情况, 你甚至可以选择忽略停止请求.
    以这种方式停止任务不会触发 WorkStopped 事件, 而是被视为任务已正常完成.
string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        powerPool.StopIfRequested();
        // Do something
    }
});
string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        powerPool.StopIfRequested(() =>
        {
            // Do something before return
            if (/* 你希望继续停止 */)
            {
                return true;
            }
            else
            {
                return false;
            }
        });
        // Do something
    }
});
string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        if (powerPool.CheckIfRequestedStop())
        {
            // Do something before return
            return;
        }
        // Do something
    }
});
powerPool.Pause();
powerPool.Pause(workID);
powerPool.Pause(workIDList);
powerPool.Resume();
powerPool.Resume(workID);
powerPool.Resume(workIDList);
powerPool.Stop();
powerPool.Stop(workID);
powerPool.Stop(workIDList);

强制停止

Stop 函数接受布尔参数 (即 forceStop)为 true 时, 即使任务逻辑中未插入 StopIfRequested(...), 它也可以停止线程, 因为将调用 Thread.Interrupt(). 线程池将在捕获 ThreadInterruptedException 后立即终止线程.
虽然这种方式比 Thread.Abort 更安全, 但从业务逻辑的角度来看, 它仍可能导致不可预知的结果, 且无法保证退出线程所需的时间, 因此应尽量避免使用强制停止.
以这种方式停止的线程将被销毁, 不会被保留.

string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        // Do something
    }
});
powerPool.Stop(true);
powerPool.Stop(workID, true);
powerPool.Stop(workIDList, true);

Wait(等待)

调用线程可以被阻塞, 直到所有任务终止.
可以使用任务 ID 作为 Wait 的参数, 确保其他任务不受影响.
Wait 的异步版本是 WaitAsync.

powerPool.Wait();
powerPool.Wait(workID);
powerPool.Wait(workIDList);

Fetch(获取)

Fetch 函数用于获取任务的结果. 调用后, 将在任务完成时返回 ExecuteResult.

通过任务 ID 获取结果

需要 workIDworkIDList 作为参数.
通常, Fetch 函数用于获取尚未开始或正在进行中的任务的结果.
此函数是阻塞的, 意味着它将暂停调用线程的执行, 直到指定的任务完成并返回结果.
对于非阻塞行为, 可以使用 FetchAsync 函数. 此函数允许异步获取任务的结果, 而不会中断调用线程的执行.

通过谓词函数获取结果

需要 谓词函数 作为参数.
它将根据谓词函数从现有结果中搜索匹配的结果集合. 谓词函数是一个接受 ExecuteResult<TResult> 作为参数并返回 bool 值的函数, 类似于 LINQ 中的 Where.
由于它从已有结果中筛选, 不会导致阻塞, 因此没有异步版本.

Fetch 的异步版本是 FetchAsync.

powerPool.Fetch(workID);
powerPool.Fetch(workIDList);
powerPool.Fetch<int>(x => x.Result >= 3);

获取已完成任务的结果

默认情况下, 为了防止内存泄漏, 线程池不存储任务执行结果. 如果你希望保留已完成任务的结果, 应将 WorkOption.ShouldStoreResult 设置为 true, 这会指示线程池在任务完成后保存结果.

清除已保存的执行结果

有三种方式可以清除已保存的执行结果:

  • PowerPoolOption.ClearResultStorageWhenPoolStart 设置为 true. 这将在线程池重新进入运行状态时清除已保存的执行结果.
PowerPool powerPool = new PowerPool(new PowerPoolOption() { ClearResultStorageWhenPoolStart = true });
  • Fetch 函数的可选参数设置为 true (Fetch(workID, true)), 这样在调用 Fetch 时, 任务 ID 对应的执行结果将被清除.
powerPool.Fetch(workID, true);
powerPool.Fetch(workIDList, true);
  • 直接调用 PowerPool.ClearResultStorage(...).
powerPool.ClearResultStorage();
powerPool.ClearResultStorage(workID);
powerPool.ClearResultStorage(workIDList);

Cancel(取消)

Cancel 函数用于取消尚未开始的任务.
可以使用任务 ID 作为 Cancel 的参数, 确保其他任务不受影响.

powerPool.Cancel();
powerPool.Cancel(workID);
powerPool.Cancel(workIDList);
⚠️ **GitHub.com Fallback** ⚠️