首页
/ WSL 容器 SDK 的 ImageProgress 数据类:镜像 pull/import/load/push 进度上报机制详解

WSL 容器 SDK 的 ImageProgress 数据类:镜像 pull/import/load/push 进度上报机制详解

2026-09-09 12:04:00作者:明树来

导读

本文围绕 WSL 仓库中 ImageProgress 数据类文档 展开,深入剖析 ImageProgress 的字段语义、ImageProgressStatus 状态机,以及它如何贯穿 C 层进度回调、WinRT 投影和 C# 异步进度接口,帮助读者掌握在 WSL 容器 SDK(WSLC)中订阅镜像操作进度的完整实践方案。

什么是 ImageProgress

ImageProgress 是 WSL 容器 SDK(WSLC)中专门用于承载镜像操作进度信息的数据类,其作用范围覆盖 pull(拉取)、import(导入)、load(加载)、push(推送)四类镜像操作。当这些操作执行时,SDK 会以异步进度回调的方式不断上报当前状态,而 ImageProgress 正是这一批进度消息在 C# 侧的标准化表示。

官方文档给出了类的完整定义:

public sealed class ImageProgress
{
    public string Id { get; }
    public ImageProgressStatus Status { get; }
    public ulong CurrentBytes { get; }
    public ulong TotalBytes { get; }
}

四个属性各司其职:

  • Id(string):当前进度消息所对应的镜像层 ID 或 digest。一次镜像操作通常由多个层组成,每个层都有独立的进度流,通过 Id 可以区分不同的层。
  • Status(ImageProgressStatus):当前层所处的工作阶段,取值来自 ImageProgressStatus 枚举。
  • CurrentBytes(ulong):当前层已处理的字节数。
  • TotalBytes(ulong):当前层的预估总字节数。

进度状态的完整枚举

ImageProgressStatus 是理解 ImageProgress.Status 的基础,其完整定义见 ImageProgressStatus 枚举文档

public enum ImageProgressStatus
{
    Unknown = 0,
    Pulling = 1,
    Waiting = 2,
    Downloading = 3,
    Verifying = 4,
    Extracting = 5,
    Complete = 6
}

这一状态序列与 Docker 客户端的层处理流程一一对应:Pulling 表示开始拉取,Waiting 表示排队等待(可能受并发层数限制),Downloading 表示正在传输数据,Verifying 表示校验校验和(Docker 中对应 "Verifying Checksum"),Extracting 表示解压展开层文件,Complete 表示该层处理完毕(对应 Docker 的 "Pull complete")。

底层 C 头文件 中可以看到这组状态值与注释的对应关系:

WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN = 0,
WSLC_IMAGE_PROGRESS_STATUS_PULLING = 1,
WSLC_IMAGE_PROGRESS_STATUS_WAITING = 2,     // "Waiting"
WSLC_IMAGE_PROGRESS_STATUS_DOWNLOADING = 3, // "Downloading"
WSLC_IMAGE_PROGRESS_STATUS_VERIFYING = 4,   // "Verifying Checksum"
WSLC_IMAGE_PROGRESS_STATUS_EXTRACTING = 5,  // "Extracting"
WSLC_IMAGE_PROGRESS_STATUS_COMPLETE = 6     // "Pull complete"

如何获取 ImageProgress

ImageProgress 不会凭空产生,它由 Session 上的镜像操作接口对外提供。参考 Session 核心类文档Session 为四类操作分别提供了同步版本和带进度上报的异步版本:

public IAsyncActionWithProgress<ImageProgress> PullImageAsync(PullImageOptions options);
public IAsyncActionWithProgress<ImageProgress> ImportImageAsync(string path, string imageName);
public IAsyncActionWithProgress<ImageProgress> LoadImageAsync(string path);
public IAsyncActionWithProgress<ImageProgress> PushImageAsync(PushImageOptions options);

这些方法返回 IAsyncActionWithProgress<ImageProgress>,消费方只需订阅其 Progress 事件即可实时收到 ImageProgress 实例。这也解释了为什么 ImageProgress 的所有属性都是只读的——它完全由 SDK 内部生成并推送,调用方只负责读取展示。

WinRT IDL 定义 中可以看到完全一致的异步签名设计,C# API 正是这一 WinRT 投影的托管形态。

从 C 回调到 WinRT 的完整链路

ImageProgress 的生成链路贯穿三层实现,理解这条链路有助于把握字段语义的出处:

  1. C 层结构体:底层 SDK 使用 WslcImageProgressMessage 承载原始进度数据:
typedef struct WslcImageProgressMessage
{
    _Out_ PCSTR id;                       // layer ID or digest
    _Out_ WslcImageProgressStatus status; // "Downloading", "Extracting", etc.
    _Out_ WslcImageProgressDetail detail;
} WslcImageProgressMessage;
  1. 兼容层转换ProgressCallback.cpp 负责将原生回调转换为 WinRT 可消费的消息结构。

  2. WinRT 包装类ImageProgress.hImageProgress.cpp 实现 ImageProgress 的 WinRT 投影,构造时从 WslcImageProgressMessage 逐字段拷贝:

ImageProgress::ImageProgress(const WslcImageProgressMessage* progress) :
    m_id(winrt::to_hstring(progress->id)),
    m_status(static_cast<ImageProgressStatus>(progress->status)),
    m_currentBytes(progress->detail.currentBytes),
    m_totalBytes(progress->detail.totalBytes)
{
}

可以看到 CurrentBytes / TotalBytes 直接来自 detail 子结构中的 currentBytes / totalBytes 字段,与文档中的 ulong 类型完全对应。

使用示例:在 C# 中订阅镜像拉取进度

文档给出的示例展示了最基础的消费方式——将 ImageProgress 格式化为一行可读文本:

void PrintImageProgress(ImageProgress progress) =>
    Console.WriteLine($"{progress.Status,-12} {progress.Id} {progress.CurrentBytes}/{progress.TotalBytes}");

这里 {progress.Status,-12} 表示状态字段左对齐、占 12 个字符宽度,输出形如:

Downloading  sha256:abc123... 10485760/31457280
Extracting   sha256:abc123... 20971520/31457280
Pull complete sha256:abc123... 31457280/31457280

结合 Session 的完整实战写法

单看 PrintImageProgress 还不够,将它接入真实操作才能发挥价值。结合 Session 文档 中的异步示例,一次带进度显示的镜像拉取可以这样写:

var pull = session.PullImageAsync(new PullImageOptions("docker.io/library/alpine:latest"));
pull.Progress = (op, progress) =>
    PrintImageProgress(progress);
await pull;

IAsyncActionWithProgress<ImageProgress>.Progress 事件的委托签名是 AsyncActionProgressHandler<ImageProgress>,两个参数分别为异步操作本身和本次进度实例。在实际应用中,往往还需要引入按 Id 分组的累计逻辑——因为同一层在 Downloading 阶段会收到大量字节更新的回调,而每个进度实例只携带本次增量对应的当前值,界面层需要自行维护每个层的最近状态。

实战注意点:TotalBytes 是预估而非精确值

在编写进度条时要特别注意 TotalBytes 的语义。在 CLI 进度渲染实现 中有这样一段关键注释:

Docker 上报的 total 是压缩后层大小的预估,实际传输的字节数可能超过该值。此时应丢弃 total,避免显示超过 100% 的计数。

对应实现中,当 current > total 时只显示当前字节数、不再拼接 /total。这意味着展示层不应把 TotalBytes 当作精确上限,进度条应做封顶处理(Math.Min(current, total)),并在 current 超出 total 时直接视为完成。

底层视角:SDK 侧的进度上报与渲染策略

深入仓库源码可以看到,ImageProgress 数据在下游消费时有两种典型形态,这也为上层 API 设计提供了参照。

原生 C 回调接口

底层 SDK 通过函数指针回调上报进度,定义于 wslcsdk.h

typedef HRESULT(CALLBACK* WslcContainerImageProgressCallback)(const WslcImageProgressMessage* progress, PVOID context);

该回调挂接在各操作选项结构体中,如 WslcPullImageOptionsprogressCallback / progressCallbackContext 字段),由兼容层 ProgressCallback.hCreateIf 工厂按需包装后转发给 WinRT 层。

CLI 终端的交互式渲染

wslc 服务的 ImageProgressCallback 展示了进度的另一种消费方式:在 VT 终端上,每个层独占一行,通过光标移动在同一行内原地重绘进度条(=====> 形式);当输出被重定向(非 VT 环境)时,则退化为按状态去重打印的日志流。其中对进度条填充、控制台宽度截断、UTF-16 代理对保护的细节处理,为自定义进度 UI 提供了现成的工程参考。

测试验证

仓库测试 WslcSdkTests.cpp 中的 ImageProgressCallback 测试用例,通过启动本地 registry、对 hello-world:latest 执行 push 操作来验证进度回调确实被触发,并断言回调收到的状态不是 UNKNOWN。这从测试角度印证了:只要挂接了回调,镜像操作期间就一定会收到带有效状态的 ImageProgress 消息。

与其他数据类的关系

ImageProgress 属于 C# Data Classes 目录 中的一员,该目录还包含 ImageInfoContainerPortMappingContainerVolumeInstallProgressServiceVersion 等数据类。与 ImageProgress 最相关的是:

  • ImageInfo:描述镜像的静态元信息(名称、ID、大小等),由 Session.GetImages() 返回,代表"结果";
  • ImageProgress:描述镜像操作的动态过程,由 PullImageAsync 等异步接口推送,代表"过程"。

二者配合可以构建完整的镜像管理 UI:用 ImageInfo 展示已安装镜像清单,用 ImageProgress 展示正在进行的拉取/推送任务。

小结

ImageProgress 虽然只是一个四字段的简单数据类,却是 WSL 容器 SDK 镜像操作体验的关键一环。理解它的关键在于把握三条线索:Status 对应完整的层处理状态机(PullingWaitingDownloadingVerifyingExtractingComplete);Id 标识具体层;CurrentBytes / TotalBytes 提供量化进度——且 TotalBytes 是预估上限,展示层需要容忍超量情况。将其接入 Session 的四个 *Async 异步接口的 Progress 事件,即可在 C# 应用中实现与 Docker CLI 相当的实时进度体验。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
858
1.35 K
docsdocs
暂无描述
Markdown
899
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
923
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.83 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
532
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
524
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
393