Libuv库(探讨)---第六节:进程相关

Python 异步网络编程实战 本小册主要讲解Python异步编程,不仅仅是讲解如何使用异步,主要的还是介绍异步的实现原理,从字节码分析,到爬虫实现,由浅入深学习Python异步的实现原理 阅读详情

索引目录:https://blog.youkuaiyun.com/knowledgebao/article/details/84776754


libuv offers considerable child process management, abstracting the platform differences and allowing communication with the child process using streams or named pipes.(libuv提供子进程的管理工作,抽象平台的差异性,允许通过stream和pipe进行线程之间的交互)

A common idiom in Unix is for every process to do one thing and do it well. In such a case, a process often uses multiple child processes to achieve tasks (similar to using pipes in shells). A multi-process model with messages may also be easier to reason about compared to one with threads and shared memory.(unix建议每个进程只做一件事并且做好。所以一个进程常常使用多个子进程来完成各种任务,类似于shell中使用多个pipe。与线程共享内存类似,含有消息的多进程模型也很简单。)

A common refrain against event-based programs is that they cannot take advantage of multiple cores in modern computers. In a multi-threaded program the kernel can perform scheduling and assign different threads to different cores, improving performance. But an event loop has only one thread. The workaround can be to launch multiple processes instead, with each process running an event loop, and each process getting assigned to a separate CPU core.(基于事件的程序想利用现代计算机的多核功能是有一定挑战性的。在多线程程序里,内核可以通过调度把不同的线程分配到不同的系统核core上来提供core的利用率。但是libuv的loop只有一个线程,通过变通的使用多进程,每个进程上运行一个loop,每个进程关联到不同的core上以达到利用多核系统。)

创建进程:

The simplest case is when you simply want to launch a process and know when it exits. This is achieved using uv_spawn.

使用uv_spawn来创建一个进程。代码如下:

UV_EXTERN int uv_spawn(uv_loop_t* loop,uv_process_t* handle,const uv_process_options_t* options);

uv_loop_t *loop;
uv_process_t child_req;
uv_process_options_t options;
void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) {
    fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal);
    uv_close((uv_handle_t*) req, NULL);
}
int main() {
    loop = uv_default_loop();

    char* args[3];
    args[0] = "mkdir";
    args[1] = "test-dir";
    args[2] = NULL;

    options.exit_cb = on_exit;
    options.file = "mkdir";
    options.args = args;

    int r;
    if ((r = uv_spawn(loop, &child_req, &options))) {
        fprintf(stderr, "%s\n", uv_strerror(r));
        return 1;
    } else {
        fprintf(stderr, "Launched process with ID %d\n", child_req.pid);
    }

    return uv_run(loop, UV_RUN_DEFAULT);
}

options必须被初始化位0,上边代码因为options是全局的,所以默认会被置为0.

args的数组最后一个参数必须是NULL。

完成调用之后,uv_process_t.pid包含的就是进程ID.

on_exit()在进程退出时,会触发。

改变参数:

在进程运行前,可以改变参数uv_process_options_t。

Set uv_process_options_t.cwd to the corresponding directory.设置运行目录。

uv_process_options_t.env is a null-terminated array of strings, each of the form VAR=VALUE used to set up the environment variables for the process. Set this to NULL to inherit the environment from the parent (this) process.运行环境。

按位或flags参数。

Setting uv_process_options_t.flags to a bitwise OR of the following flags, modifies the child process behaviour:

  • UV_PROCESS_SETUID - sets the child’s execution user ID to uv_process_options_t.uid.
  • UV_PROCESS_SETGID - sets the child’s execution group ID to uv_process_options_t.gid.

Changing the UID/GID is only supported on Unix, uv_spawn will fail on Windows with UV_ENOTSUP.

  • UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS - No quoting or escaping of uv_process_options_t.args is done on Windows. Ignored on Unix.
  • UV_PROCESS_DETACHED - Starts the child process in a new session, which will keep running after the parent process exits. See example below.

分离过程

可以创建和父进程无关的子进程,使用UV_PROCESS_DETACHED标记。不受父进程的影响,父进程关闭不影响子进程的运行。可以用来写守候等不受父进程影响的子进程。举例如下:

int main() {
    loop = uv_default_loop();

    char* args[3];
    args[0] = "sleep";
    args[1] = "100";
    args[2] = NULL;

    options.exit_cb = NULL;
    options.file = "sleep";
    options.args = args;
    options.flags = UV_PROCESS_DETACHED;

    int r;
    if ((r = uv_spawn(loop, &child_req, &options))) {
        fprintf(stderr, "%s\n", uv_strerror(r));
        return 1;
    }
    fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid);
    uv_unref((uv_handle_t*) &child_req);

    return uv_run(loop, UV_RUN_DEFAULT);

虽然使用了UV_PROCESS_DETACHED,但是句柄还在父进程那里,如果想完全失去读子进程的控制,需要调用uv_unref接口,完全释放对子进程的控制。

向进程发送信号

在进程执行的过程中,可以通过发送信号来控制进程的执行。当然 SIGTERM, SIGINT and SIGKILL也会导致线程终止,具体参考https://blog.youkuaiyun.com/qq562029186/article/details/70132719

UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
UV_EXTERN int uv_kill(int pid, int signum);

如果调用uv_process_kill关闭进程的话,别忘记调用uv_close函数。

信号

libuv针对Unix提供了一些信号,有些也适用于Windows.

使用uv_signal_init()初始化,它与一个循环关联。要侦听该处理程序上的特定信号,使用uv_signal_start()处理程序函数。每个处理程序只能与一个信号编号相关联,连续调用 uv_signal_start()后边的覆盖先前信号。使用uv_signal_stop()停止信号监听。下边提供一个小例子供参考:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <uv.h>

uv_loop_t* create_loop()
{
    uv_loop_t *loop = malloc(sizeof(uv_loop_t));
    if (loop) {
      uv_loop_init(loop);
    }
    return loop;
}

void signal_handler(uv_signal_t *handle, int signum)
{
    printf("Signal received: %d\n", signum);
    uv_signal_stop(handle);
}

// two signal handlers in one loop
void thread1_worker(void *userp)
{
    uv_loop_t *loop1 = create_loop();

    uv_signal_t sig1a, sig1b;
    uv_signal_init(loop1, &sig1a);
    uv_signal_start(&sig1a, signal_handler, SIGUSR1);

    uv_signal_init(loop1, &sig1b);
    uv_signal_start(&sig1b, signal_handler, SIGUSR1);

    uv_run(loop1, UV_RUN_DEFAULT);
}

// two signal handlers, each in its own loop
void thread2_worker(void *userp)
{
    uv_loop_t *loop2 = create_loop();
    uv_loop_t *loop3 = create_loop();

    uv_signal_t sig2;
    uv_signal_init(loop2, &sig2);
    uv_signal_start(&sig2, signal_handler, SIGUSR1);

    uv_signal_t sig3;
    uv_signal_init(loop3, &sig3);
    uv_signal_start(&sig3, signal_handler, SIGUSR1);

    while (uv_run(loop2, UV_RUN_NOWAIT) || uv_run(loop3, UV_RUN_NOWAIT)) {
    }
}

int main()
{
    printf("PID %d\n", getpid());

    uv_thread_t thread1, thread2;

    uv_thread_create(&thread1, thread1_worker, 0);
    uv_thread_create(&thread2, thread2_worker, 0);

    uv_thread_join(&thread1);
    uv_thread_join(&thread2);
    return 0;
}

上述监听回调会触发4次监听。

子进程I/O

子进程有其自身的一组文件描述符,用0,1和2的分别表示stdin,stdout和stderr。有时我们可能希望子进程与父进程共享文件描述符。libuv支持 继承文件描述符。

int main() {
    loop = uv_default_loop();

    /* ... */

    options.stdio_count = 3;
    uv_stdio_container_t child_stdio[3];
    child_stdio[0].flags = UV_IGNORE;
    child_stdio[1].flags = UV_IGNORE;
    child_stdio[2].flags = UV_INHERIT_FD;
    child_stdio[2].data.fd = 2;
    options.stdio = child_stdio;

    options.exit_cb = on_exit;
    options.file = args[0];
    options.args = args;

    int r;
    if ((r = uv_spawn(loop, &child_req, &options))) {
        fprintf(stderr, "%s\n", uv_strerror(r));
        return 1;
    }

    return uv_run(loop, UV_RUN_DEFAULT);
}

UV_IGNORE被重定向到/dev/null

UV_INHERIT_FD继承父进程的I/O,需要在data.fd中,设置父进程的描述符。

同理,子进程可以继承父进程的Stream,举例如下:


    args[1] = NULL;

    /* ... finding the executable path and setting up arguments ... */

    options.stdio_count = 3;
    uv_stdio_container_t child_stdio[3];
    child_stdio[0].flags = UV_IGNORE;
    child_stdio[1].flags = UV_INHERIT_STREAM;
    child_stdio[1].data.stream = (uv_stream_t*) client;
    child_stdio[2].flags = UV_IGNORE;
    options.stdio = child_stdio;

    options.exit_cb = cleanup_handles;
    options.file = args[0];
    options.args = args;

    // Set this so we can close the socket after the child process exits.
    child_req.data = (void*) client;
    int r;
    if ((r = uv_spawn(loop, &child_req, &options))) {
        fprintf(stderr, "%s\n", uv_strerror(r));

管道

管道不像linux下的符号“|”或者pipe,管道是用于两个进程之间进行通信的方法。具体如下:

父子管道:

父进程在创建子进程的时候uv_spawn,可以通过设置 uv_stdio_container_t.flags 参数,来设置父子进程之间的单向或双向通信, uv_stdio_container_t.flags可以是UV_CREATE_PIPE 、 UV_READABLE_PIPE or UV_WRITABLE_PIPE的一个或多个。可以同时设置多个,占不同的二进制位。UV_CREATE_PIPE 、 UV_READABLE_PIPE or UV_WRITABLE_PIPE都是从子进程的角度来看。

Arbitrary process IPC

Since domain sockets [1] can have a well known name and a location in the file-system they can be used for IPC between unrelated processes. The D-BUS system used by open source desktop environments uses domain sockets for event notification. Various applications can then react when a contact comes online or new hardware is detected. The MySQL server also runs a domain socket on which clients can interact with it.

When using domain sockets, a client-server pattern is usually followed with the creator/owner of the socket acting as the server. After the initial setup, messaging is no different from TCP, so we’ll re-use the echo server example.

pipe-echo-server/main.c

void remove_sock(int sig) {
    uv_fs_t req;
    uv_fs_unlink(loop, &req, PIPENAME, NULL);
    exit(0);
}

int main() {
    loop = uv_default_loop();

    uv_pipe_t server;
    uv_pipe_init(loop, &server, 0);

    signal(SIGINT, remove_sock);

    int r;
    if ((r = uv_pipe_bind(&server, PIPENAME))) {
        fprintf(stderr, "Bind error %s\n", uv_err_name(r));
        return 1;
    }
    if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) {
        fprintf(stderr, "Listen error %s\n", uv_err_name(r));
        return 2;
    }
    return uv_run(loop, UV_RUN_DEFAULT);
}

We name the socket echo.sock which means it will be created in the local directory. This socket now behaves no different from TCP sockets as far as the stream API is concerned. You can test this server using socat:

$ socat - /path/to/socket

A client which wants to connect to a domain socket will use:

void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb);

where name will be echo.sock or similar. On Unix systems, name must point to a valid file (e.g. /tmp/echo.sock). On Windows, name follows a \\?\pipe\echo.sock format.

进程相关API

/* uv_spawn() options. */
typedef enum {
  UV_IGNORE         = 0x00,
  UV_CREATE_PIPE    = 0x01,
  UV_INHERIT_FD     = 0x02,
  UV_INHERIT_STREAM = 0x04,

  /*
   * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
   * determine the direction of flow, from the child process' perspective. Both
   * flags may be specified to create a duplex data stream.
   */
  UV_READABLE_PIPE  = 0x10,
  UV_WRITABLE_PIPE  = 0x20,

  /*
   * Open the child pipe handle in overlapped mode on Windows.
   * On Unix it is silently ignored.
   */
  UV_OVERLAPPED_PIPE = 0x40
} uv_stdio_flags;

typedef struct uv_stdio_container_s {
  uv_stdio_flags flags;

  union {
    uv_stream_t* stream;
    int fd;
  } data;
} uv_stdio_container_t;

typedef struct uv_process_options_s {
  uv_exit_cb exit_cb; /* Called after the process exits. */
  const char* file;   /* Path to program to execute. */
  /*
   * Command line arguments. args[0] should be the path to the program. On
   * Windows this uses CreateProcess which concatenates the arguments into a
   * string this can cause some strange errors. See the note at
   * windows_verbatim_arguments.
   */
  char** args;
  /*
   * This will be set as the environ variable in the subprocess. If this is
   * NULL then the parents environ will be used.
   */
  char** env;
  /*
   * If non-null this represents a directory the subprocess should execute
   * in. Stands for current working directory.
   */
  const char* cwd;
  /*
   * Various flags that control how uv_spawn() behaves. See the definition of
   * `enum uv_process_flags` below.
   */
  unsigned int flags;
  /*
   * The `stdio` field points to an array of uv_stdio_container_t structs that
   * describe the file descriptors that will be made available to the child
   * process. The convention is that stdio[0] points to stdin, fd 1 is used for
   * stdout, and fd 2 is stderr.
   *
   * Note that on windows file descriptors greater than 2 are available to the
   * child process only if the child processes uses the MSVCRT runtime.
   */
  int stdio_count;
  uv_stdio_container_t* stdio;
  /*
   * Libuv can change the child process' user/group id. This happens only when
   * the appropriate bits are set in the flags fields. This is not supported on
   * windows; uv_spawn() will fail and set the error to UV_ENOTSUP.
   */
  uv_uid_t uid;
  uv_gid_t gid;
} uv_process_options_t;

/*
 * These are the flags that can be used for the uv_process_options.flags field.
 */
enum uv_process_flags {
  /*
   * Set the child process' user id. The user id is supplied in the `uid` field
   * of the options struct. This does not work on windows; setting this flag
   * will cause uv_spawn() to fail.
   */
  UV_PROCESS_SETUID = (1 << 0),
  /*
   * Set the child process' group id. The user id is supplied in the `gid`
   * field of the options struct. This does not work on windows; setting this
   * flag will cause uv_spawn() to fail.
   */
  UV_PROCESS_SETGID = (1 << 1),
  /*
   * Do not wrap any arguments in quotes, or perform any other escaping, when
   * converting the argument list into a command line string. This option is
   * only meaningful on Windows systems. On Unix it is silently ignored.
   */
  UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
  /*
   * Spawn the child process in a detached state - this will make it a process
   * group leader, and will effectively enable the child to keep running after
   * the parent exits.  Note that the child process will still keep the
   * parent's event loop alive unless the parent process calls uv_unref() on
   * the child's process handle.
   */
  UV_PROCESS_DETACHED = (1 << 3),
  /*
   * Hide the subprocess console window that would normally be created. This
   * option is only meaningful on Windows systems. On Unix it is silently
   * ignored.
   */
  UV_PROCESS_WINDOWS_HIDE = (1 << 4)
};

/*
 * uv_process_t is a subclass of uv_handle_t.
 */
struct uv_process_s {
  UV_HANDLE_FIELDS
  uv_exit_cb exit_cb;
  int pid;
  UV_PROCESS_PRIVATE_FIELDS
};

UV_EXTERN int uv_spawn(uv_loop_t* loop,
                       uv_process_t* handle,
                       const uv_process_options_t* options);
UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
UV_EXTERN int uv_kill(int pid, int signum);
UV_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*);

uv_spawn:创建子进程。
uv_process_kill:杀掉子进程,通过进程结构体。
uv_kill:杀掉子进程,通过进程ID。
uv_process_get_pid:获取进程号。

参考文章:

http://docs.libuv.org/en/v1.x/process.html


有任何问题,请联系:knowledgebao@163.com

spawn:一个简单的“ uv_spawn”包装器API即可执行和管理子进程,并行异步PHP用于阻止IO 产生 一个简单的uv_spawn包装器API,用于执行和管理子进程(用于阻止I / O的并行/异步PHP)。 该软件包使用Node.js库的 (PHP扩展 )的功能。 它的uv_spawn函数用于启动进程。 性能是一个更好的选择到了pcntl扩展,或使用proc_open 。 如果未安装libuv ,则此软件包将回退以使用[symfony / process]。 此程序包是我们的程序包的一部分,用于处理任何阻塞的I / O进程,而这些阻塞I / O进程不能被本地处理。 要了解更多关于libuv功能阅读在线教程。 安装 composer require symplely/spawn 如果可用,此软件包将使用libuv功能。 执行以下操作之一来安装。 对于像Debian这样的发行版,Ubuntu ... apt-get install libuv1-dev php-pear -y 立即下载

相关推荐

自偏置电流镜设计实例

自偏置电流镜设计实例 一、概述 ​ 众所周知,电流镜属于模拟电路设计中的一个基本模块,可为其他模块提供偏置电流,例如在放大器中提供偏置电流以形成尾电流源并确定直流偏置点。本文将会介绍一种自偏置的电流镜,从原理出发,并以0.18um的工艺进行设计和仿真。 二、原理 ​ 如图一所示的电路,也称之为Beta-multiply reference电路,其中M2的尺寸是M1的k倍。M3复制M4的电流,M2和M1的漏极电流相同,但是VGS并不相等。其中 VGS=2IμnCoxW/...

aonuanjiang的博客 1万+

libuv学习笔记(10)

libuv学习笔记(10) uv_process_t数据结构与相关函数

paohui0134的博客 1802

python语言下使用opencv接口cv2.VideoCapture()接口调用海康机器人工业相机

文章目录 目录 文章目录 前言 一、opencv接口介绍 二、调用海康机器人工业相机 1.使用海康机器人工业相机的前提 2.调用海康机器人工业相机进行显示 3.调用海康机器人工业相机进行存图 4.调用海康机器人工业相机存视频 5.调用海康机器人工业相机进行简单图像处理 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下.

qq_39570716的博客 1万+

libuv库学习笔记-processes

在函数。

实力派,无需多言! 490

华为星闪SLE实战:手把手教你用HarmonyOS开发智能家居控制应用(附完整代码)

本文详细介绍了如何利用华为星闪SLE技术,结合HarmonyOS开发智能家居控制应用。通过对比传统无线技术,阐述了星闪SLE在低时延、高可靠性和高并发方面的优势,并提供了从环境搭建、设备发现、连接管理到核心控制代码的完整实战教程,帮助开发者快速上手这一无线短距通信技术。

bert9linguist的博客 507

科研党必备:5分钟搞定MATLAB闪退问题(含R2020a-R2023b各版本适配)

本文针对科研人员常见的MATLAB闪退问题,提供了从R2020a到R2023b各版本的适配解决方案。通过分析六大诱因和版本定制化修复方法,帮助用户快速诊断和解决闪退问题,包括内存优化、高级调试和预防性维护等实用技巧,确保科研计算的连续性和稳定性。

t1u2v的博客 1967

Libuv 句柄优雅关闭

当服务端与客户端处于连接状态时,如果客户端应用进程突然关闭,我们可以直接使用Libuv中的uv_close暴力断开两端的连接...

田螺姑娘的博客 1547

计算机模拟爆破过程,基于LSDYNA岩石爆破模拟建模分析

原标题:基于LSDYNA岩石爆破模拟建模分析 Ls Dyna岩石爆破模拟仿真作者:dyna_focus擅长领域:dyna/abaqus/hypermesh一、 数值模型的建立1.1 单元及算法的选择岩石,炸药,空气都采用solid164实体单元。岩石采用常应力实体单元,该种单元属于纯粹的lagrange算法,该种算法单元网格附着在材料上,随着材料的流动而产生单元网格的变形,但是在结构变形巨大时,有...

weixin_29494379的博客 7317

冷月手撕408之操作系统(5)-进程概述

操作系统的进程概述主要是介绍了进程的概念,进程的组成(进程实体)、进程的特征、进程的五状态模型、进程控制,其中重点掌握PCB、五状态模型及其状态转换。 主要的重点冷月做出了标识,知识点如下图(pdf版或xmind源文件请关注公众号:学长冷月,回复操作系统)。 冷月点睛 程序是静态的存储在计算机硬盘里面的计算机代码,而进程是程序在数据上的一次动态执行。 进程实体也叫进程映像,包括程序段、数据段、PCB。是进程的静态组成。 PCB,进程控制块,进程存在的唯一标识,常驻内存中。 进程最主要、最基本的特征是动态性

学长冷月的博客 2216

【YOLO26创新改进】TGRS 2026 | Transformer变体改进篇 | 使用CGTA曲率引导令牌注意力,改善结构与纹理的整体协调,适合遥感小目标检测、旋转目标检测、实例分割任务

本文在YOLO26目标检测模型中引入CGTA曲率引导令牌注意力模块,依据曲率显著性与特征可靠性,从高分辨率特征图中筛选少量关键令牌,再让全部位置与这些代表性特征进行全局交互,从而以较低计算和显存开销建立远距离目标、背景及跨尺度结构之间的联系;该模块能够重点强化车辆、舰船、飞机、建筑等目标的边缘、转角和弯曲轮廓,改善小目标、密集目标及旋转目标的特征完整性与定位稳定性,并通过可靠性门控抑制噪声和伪边缘,通过标准注意力与曲率注意力融合避免平坦区域被过度增强。

AI魔改博士-中大博士 47

EMI辐射发射超标案例

EMI辐射发射超标案例

让你爱上电路设计 8503

libuv 入门到使用完整指南:跨平台异步 I/O 事件循环库怎么装、怎么用

假设你正在用 C 写一个需要同时服务多个客户端的程序:Linux 上可以用 epoll,Windows 上却要换成 IOCP,两套事件机制意味着两套代码。libuv 解决的就是这个问题——它把各平台的 I/O 事件机制封装成同一套事件循环 API,你的程序只写一遍,在 Linux、macOS、Windows 上都能跑。它就是 Node.js 底层的跨平台异步 I/O 支持库,同时也被 Luvit、

gitblog_00123的博客 737

LabVIEW进行MQTT通信及数据解析

该文章介绍了LabVIEW的MQTT通信的开源VI控制,以及如果进行数据的解析,特别是一些需要注意的点

heda3的博客 4106

Rust 标准库 IO 体系重构设计:RFC 0517(std::io 与 std::os 大改)深度解析

本文围绕 Rust RFC 0517([text/0517-io-os-reform.md](https://link.gitcode.com/i/f84db3d5efd784b2386cba6eb23559c1))展开,系统讲解 2014 年底 Rust 团队为 `std::io` / `std::os` 两大模块在 API 稳定化前进行的整体重设计:从 `Read`/`Write` trai

gitblog_00008的博客 419

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

TechEmpower Framework Benchmarks 中的 aioworkers 基准测试实现:基于 asyncio 的可配置 Worker 架构全解析

本文面向希望理解 aioworkers 框架在 TechEmpower Framework Benchmarks(TFB)中如何被接入与压测的开发者,完整解析该框架在基准项目中的目录结构、配置驱动方式、HTTP 路由与 PostgreSQL 数据库测试实现,以及容器化启动与结果验证闭环。读完本文,你将掌握 aioworkers 以 YAML 配置声明 Worker、以 uvloop + httpt

gitblog_00590的博客 155

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

DDIA 中文翻译:数据系统经典第二版 14 章完整读法

ddia 项目是数据系统经典《Designing Data-Intensive Applications》(DDIA) 的中文翻译,第二版 14 章齐全,另有第一版 12 章可对照。它回答一个问题:数据系统怎么选、怎么组合。最直接的方式是线上版阅读,或本地打开 content/zh/ 下的 Markdown 文件。 ## 你拿到了什么:内容与边界 仓库的核心是 content/zh/ 下的第二

gitblog_00022的博客 368

DeepSeek-V4-Pro-Qwen3.5-9B的5个实战应用场景:数学解题、STEM问答与推理工作流

如果你想在本地跑一个**推理能力强的 9B 数学解题与 STEM 问答模型**,DeepSeek-V4-Pro-Qwen3.5-9B 值得一试。它是由 DeepSeek-V4-Pro(Max Effect 模式)蒸馏得到的 9B 推理微调模型,配套 Q2_K 到 BF16 全套 GGUF 量化版本,开箱即用 llama.cpp 部署。本文带你快速上手,并拆解 5 个最值得落地的实战场景。 ##

gitblog_00515的博客 396

XMRig 6.26 CPU/GPU 统一挖矿与 RandomX 基准测试:从配置到投产的完整实战指南

XMRig 是一款开源、跨平台的统一挖矿程序,v6.26.0 同时支持 RandomX、KawPow、CryptoNight 与 GhostRider 四大算法家族。本文带你完成从获取、最小配置、深度调优到不停机热更新的全流程操作,所有参数默认值均取自仓库源码,行号可查证。全文覆盖后端选型、JSON 配置、命令行速查、基准测试、HTTP API 与高频排障,读完即可独立投产一台 CPU/GPU 混

gitblog_00122的博客 958

XERJ 与 Elasticsearch 全维对标:88 项基准矩阵的测量方法、分数卡与复现指南

> **导读**:本文围绕仓库中的 `demo/playbooks/BENCHMARK_VS_ES.md`(由 `bench-matrix.mjs` 自动生成的 XERJ vs Elasticsearch 分数卡)展开,系统讲解这套对标基准的测量方法论、全部 88 项对比结果、4 个已知的读写混合场景短板及其源码级根因,并给出在本地完整复现每一行数据的操作步骤。读完本文,你将掌握如何用同一套 HT

gitblog_00792的博客 641

Libuv 各个回调(异步)事件的调用时机

下面有一个应用场景,与uv_close的调用时机有关,服务端有一个心跳检测机制,判断连接上来每个会话(Session)是否具有活性。其中,ClientHeartCheck是一个定时器事件,定时时间为3000。

田螺姑娘的博客 1396

libuv进程管理终极指南:子进程创建与IPC通信技术详解

libuv作为Node.js、Redis等知名项目的底层异步I/O库,其强大的进程管理和IPC通信能力是构建高性能应用的关键技术。本文将深入解析libuv的子进程创建机制、标准输入输出重定向以及多种进程间通信方式,帮助你掌握跨平台异步I/O的核心技术。🚀 ## 什么是libuv进程管理? libuv提供了一套完整的进程管理API,支持跨平台的子进程创建、管理和通信。通过`uv_process

gitblog_00542的博客 676

libuv进程与线程管理:多任务处理的艺术

本文深入探讨了libuv库在多任务处理方面的核心能力,涵盖了子进程创建与管理、进程间通信机制、线程池配置与工作队列管理、信号处理与进程控制,以及同步原语的实现。通过详细的代码示例和架构图解析,展示了libuv如何在不同操作系统上提供统一的API接口,帮助开发者构建高效、稳定的异步多进程和多线程应用程序。文章从基础概念到高级应用,全面解析了libuv在多任务处理中的设计理念和最佳实践。 ## l...

gitblog_00615的博客 1133

libuv库学习笔记-Timers-Event loop reference count等

本章介绍的工具和技术对于常见的任务非常的实用。libuv吸收了中所涵盖的一些模式,并在此基础上对API做了少许的改动。本章还包含了一些无需用完整的一章来介绍的libuv API。

实力派,无需多言! 869

使用libuv搭建tcp服务器与客户端通信

目录参考资料基础知识异步阻塞轮询阻塞回调异步回调libuv基础新建项目网络IOTCPserverclientAPI简介1.uv_tcp_init2.uv_ip4_addr3.uv_tcp_bind4.uv_listen5.uv_connection_cb6.uv_accept7.uv_read_start8.uv_buf_t 和 uv_buf_init9.uv_close10.uv_write1...

博客 2509

wps取消循环引用_从 unref 看事件循环

原文发表于 追光 の 繁星描述引用 nodejs.cn 的描述 调用时,活动的 Timeout 对象不需要 Node.js 事件循环保持活动状态。 如果没有其他活动保持事件循环运行,则进程可以在调用 Timeout 对象的回调之前退出。 多次调用 timeout.unref() 将无效。 调用 timeout.unref() 会创建一个内部定时器,它将唤醒 Node.js 事件循环。 创建太多这些...

weixin_32200729的博客 481
上一篇: Libuv库(探讨)---第五节:线程相关
下一篇: Libuv库(探讨)---第七节:高级调度
knowledgebao
博客等级 码龄15年 401粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值