• libuv工作队列


    1、说明

    libuv 提供了一个线程池,可用于运行用户代码,libuv 中的工作队列中的任务会在线程池中执行

    libuv 中的线程池在内部用于运行所有文件系统操作以及 getaddrinfo()getnameinfo() 请求

    libuv 中的线程池的默认数量为4,可以在启动时修改环境变量 UV_THREADPOOL_SIZE 来修改,最大值为 1024(1.30.0版本之前是128)

    libuv 中的线程池是全局的,并在所有事件循环之间共享,当特定的函数利用 uv_queue_work() 方法使用工作队列时,libuv 会预分配线程池,以较小的内存开销(128个线程为1MB),来提高线程性能

    以下三种类型的操作会在全局线程池中进行:

    1. 文件系统操作;
    2. DNS函数(getaddrinfo 和 getnameinfo);
    3. 使用 uv_queue_work() 调度的用户代码;

    需要注意的是,即使使用了线程池,libuv 的方法也不是线程安全的

    2、API

    2.1、uv_queue_work

    int uv_queue_work(uv_loop_t* loop, 
                      uv_work_t* req, 
                      uv_work_cb work_cb, 
                      uv_after_work_cb after_work_cb);
    

    添加一个任务到工作队列中,在主线程中调用

    loop: 事件循环

    req: 传入到任务的数据,一般使用 req.data 参数传递

    work_cb: 执行方法

    after_work_cb: 执行方法完成后执行

    work_cb 方法会在函数中执行,after_work_cb 方法在创建线程中执行

    void (*uv_work_cb)(uv_work_t* req);
    void (*uv_after_work_cb)(uv_work_t* req, int status);
    

    如果调用 uv_cancel 方法取消了队列,则 uv_after_work_cbstatusUV_ECANCELED

    2.2、uv_cancel

    int uv_cancel(uv_req_t* req);
    

    取消未执行的队列中的任务,在任务中调用

    req 为任务的参数

    如果调用此方法取消了任务,则 after_work_cb 回调函数的 status 的值为 UV_ECANCELED

    3、代码示例

    #include <iostream>
    #include <pthread.h>
    #include <unistd.h>
    #include <uv.h>
    
    void print(uv_work_t *req)
    {
        sleep(1);
        long num = (long)req->data;
        printf("thread id is: %ld, num is: %d
    ", uv_thread_self(), num);
    }
    
    void after_print(uv_work_t *req, int status)
    {
        printf("after print, req data is %d, status is %d
    ", req->data, status);
    }
    
    int main()
    {
        uv_loop_t *loop = uv_default_loop();
        uv_work_t req[5];
    
        for (int index = 0; index < 5; index++)
        {
            req[index].data = (void *)(long)index;
            uv_queue_work(loop, &req[index], print, after_print);
            sleep(1);
        }
    
        return uv_run(loop, UV_RUN_DEFAULT);
    }
    

    示例中的代码,每次执行 print() 方法都是在不同线程中,after_print() 方法和 main() 方法在同一个线程中

  • 相关阅读:
    .net Winform 32位桌面应用程序突破系统2G内存限制,解决内存溢出问题
    .Net Core WebAPI Swagger Failed to load API definition
    MySql 安装详细步骤
    Vue ElementUI 按需引入提示Cannot find module 'babelpresetes2015'
    复制label标签上的文本
    3D游戏的碰撞检测是如何实现的?
    flex布局定位二
    flex布局定位一
    k8s工作负载、服务、pod
    应用内moniter
  • 原文地址:https://www.cnblogs.com/sherlock-lin/p/14342906.html
Copyright © 2020-2023  润新知