You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何简化ILGPU内核加载时泛型函数的类型参数传递?

问题描述

希望简化ILGPU中加载内核的语句,避免传递冗长的泛型类型参数,例如当前的写法:

var kernel = accelerator_.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>>(RMatrixKernels.AdditionKernel);

尝试用包装类实现简化但未成功:

public class KernelWrapper
{
    public Delegate Kernel { get; private set; }

    public KernelWrapper(Delegate kernel)
    {
        Kernel = kernel;
    }
}

请问该如何实现简化?

完整源代码:

using ILGPU;
using ILGPU.Runtime;
using System;
using System.Collections.Generic;

public class RMatrixKernels
{
    public static void AdditionKernel(Index2D index, ArrayView2D<int, Stride2D.DenseX> matrixA, ArrayView2D<int, Stride2D.DenseX> matrixB, ArrayView2D<int, Stride2D.DenseX> result)
    {
        result[index] = matrixA[index] + matrixB[index];
    }

    public static void ScalarMultiplyKernel(
        Index2D index,
        ArrayView2D<int, Stride2D.DenseX> aView, int scalar,
        ArrayView2D<int, Stride2D.DenseX> cView)
    {
        cView[index] = aView[index] * scalar;
    }
}

public class RMatrix
{
    private int[,] matrix_;
    public int Rows { get; private set; }
    public int Cols { get; private set; }

    private static Accelerator accelerator_;

    static RMatrix()
    {
        var context_ = Context.CreateDefault();
        accelerator_ = context_.GetPreferredDevice(preferCPU: true).CreateAccelerator(context_);
    }

    public RMatrix(int rows, int cols)
    {
        Rows = rows;
        Cols = cols;
        matrix_ = new int[rows, cols];
    }

    public RMatrix(int[,] arr)
    {
        Rows = arr.GetLength(0);
        Cols = arr.GetLength(1);
        matrix_ = new int[Rows, Cols];
        Array.Copy(arr, matrix_, arr.Length);
    }

    public static RMatrix operator +(RMatrix a, RMatrix b)
    {
        if (a.Rows != b.Rows || a.Cols != b.Cols)
            throw new ArgumentException("Matrix dimensions must match for addition.");

        var deviceMatrixA = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols));
        var deviceMatrixB = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols));
        var deviceResult = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols));

        deviceMatrixA.CopyFromCPU(a.matrix_);
        deviceMatrixB.CopyFromCPU(b.matrix_);

        //TODO: 
        var kernel = accelerator_.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>>(RMatrixKernels.AdditionKernel);

        kernel((a.Rows, a.Cols), deviceMatrixA.View, deviceMatrixB.View, deviceResult.View);

        accelerator_.Synchronize();

        int[,] hostResult = new int[a.Rows, a.Cols];
        deviceResult.CopyToCPU(hostResult);

        deviceMatrixA.Dispose();
        deviceMatrixB.Dispose();
        deviceResult.Dispose();

        return new RMatrix(hostResult);
    }

    public static RMatrix operator *(RMatrix a, int scalar)
    {
        var deviceMatrixA = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols));
        var deviceResult = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols));

        deviceMatrixA.CopyFromCPU(a.matrix_);

        //TODO: 
        var kernel = accelerator_.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<int, Stride2D.DenseX>, int, ArrayView2D<int, Stride2D.DenseX>>(RMatrixKernels.ScalarMultiplyKernel);

        kernel((a.Rows, a.Cols), deviceMatrixA.View, scalar, deviceResult.View);

        accelerator_.Synchronize();

        int[,] hostResult = new int[a.Rows, a.Cols];
        deviceResult.CopyToCPU(hostResult);

        deviceMatrixA.Dispose();
        deviceResult.Dispose();

        return new RMatrix(hostResult);
    }

    public void Show()
    {
        for (int i = 0; i < Rows; i++)
        {
            for (int j = 0; j < Cols; j++)
            {
                Console.Write(matrix_[i, j] + "\t");
            }
            Console.WriteLine();
        }
    }
}

public static class Program
{
    static void Main()
    {
        int[,] hostMatrixA = {
                        { 1, 2, 3 },
                        { 4, 5, 6 },
                        { 7, 8, 9 }
                    };
        int[,] hostMatrixB = {
                        { 9, 8, 7 },
                        { 6, 5, 4 },
                        { 3, 2, 1 }
                    };

        RMatrix a = new RMatrix(hostMatrixA);
        RMatrix b = new RMatrix(hostMatrixB);

        RMatrix c = a + b;
        RMatrix d = a * 10;

        Console.WriteLine("Matrix A + B:");
        c.Show();
        Console.WriteLine("\nMatrix A * 10:");
        d.Show();
    }
}
解决方案

方法:利用C#类型推断封装扩展方法

给Accelerator创建扩展方法,让编译器自动推断内核方法的泛型参数,无需手动指定:

public static class AcceleratorExtensions
{
    // 适配3个参数的内核(索引+3个参数)
    public static Action<Index2D, T1, T2, T3> LoadAutoGroupedStreamKernel<T1, T2, T3>(this Accelerator accelerator, Action<Index2D, T1, T2, T3> kernel)
    {
        return accelerator.LoadAutoGroupedStreamKernel<Index2D, T1, T2, T3>(kernel);
    }

    // 适配4个参数的内核(索引+4个参数)
    public static Action<Index2D, T1, T2, T3, T4> LoadAutoGroupedStreamKernel<T1, T2, T3, T4>(this Accelerator accelerator, Action<Index2D, T1, T2, T3, T4> kernel)
    {
        return accelerator.LoadAutoGroupedStreamKernel<Index2D, T1, T2, T3, T4>(kernel);
    }
}

使用方式

添加扩展方法后,直接传入内核方法组即可,编译器会自动推断泛型参数:

// 加法内核加载
var kernel = accelerator_.LoadAutoGroupedStreamKernel(RMatrixKernels.AdditionKernel);
// 标量乘法内核加载
var kernel = accelerator_.LoadAutoGroupedStreamKernel(RMatrixKernels.ScalarMultiplyKernel);

原包装类失败原因

之前的KernelWrapper仅存储Delegate类型,但ILGPU的LoadAutoGroupedStreamKernel需要明确的强类型委托来生成GPU内核代码,Delegate无法让编译器推断出具体泛型参数,因此无法正确加载内核。而扩展方法通过强类型委托,让编译器自动完成泛型参数推断,间接调用ILGPU的原始方法。


内容的提问来源于stack exchange,提问作者user366312

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:18:11