微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C# 不安全性能与非托管 PInvoke 调用

如何解决C# 不安全性能与非托管 PInvoke 调用

我正在运行一个处理位图图像的应用程序。现在我正在寻找一种快速方法来交换“Format24bppRgb”位图图像的“红色”和“蓝色”值。在我的 C# 代码中,我的第一次尝试是使用不安全的代码片段:

var bmpData = bmp.LockBits(new Rectangle(0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,bmp.PixelFormat);
unsafe
{
    byte* array = (byte*)bmpData.Scan0.ToPointer();
    byte temp;
    for (int x = 0; x < bmp.Width * bmp.Height * 3; x = x + 3) {
        temp = *(array + x + 2);
        *(array + x + 2) = *(array + x);
        *(array + x) = temp;
    }
}

对于我使用的位图大小,这大约需要 50-70 毫秒。现在我尝试使用 pinvoke 调用在外部库(基于 C++)中完成这项工作:

[DllImport("ByteSwitch.dll")] 
public static extern IntPtr ChangeRB(IntPtr data,int width,int height);

data = ChangeRB(bmpData.Scan0,bmp.Height);

定义如下:

extern "C" __declspec(dllexport) void* ChangeRB(void* xArray,int xHeight,int xWidth);

void* ChangeRB(void* array,int height,int width)
{
    unsigned char* _array = (unsigned char*)array;
    char temp;
    for (int x = 0; x < height * width * 3; x = x + 3)
    {
        temp = _array[x + 2];
        _array[x + 2] = _array[x];
        _array[x] = temp;
    }
    return _array;
}

这个调用大约需要 1 毫秒!所以我无法解释这里的巨大性能差异 - 还是非托管 pinvoke 真的比“不安全”代码片段快得多?

解决方法

性能问题不是来自互操作,也不是来自 C#,而是因为您在循环中使用了位图的 resp = b'\rSW10 [standalone: master] > show interfaces ethernet 1/26 status\r\r\n\x1b[?1h\x1b=\r\r\nPort Operational state Speed Negoti \x08ation \r\n---- ----------------- ----- ------ \x08----- \r\nEth1/26 Up 10 Gbps No-Neg \x08otiation \r\n\r\x1b[K\x1b[?1l\x1b>\rE2E-M9958-102Y-SW10 [standalone: master] > \r\r\n\rSW10 [standalone: master] > ' decoded_resp = resp.decode("utf-8") # "utf-8" is replaceable by any other type of character-set. print(decoded_resp ) Width。两者都在内部call a GDI Plus API

Height

请注意,在 C/C++ 情况下您不会这样做……您传递的是预先计算的高度和宽度。因此,如果您为此更改 C# 版本:

public int Width {
    get {
        int width; 
 
        int status = SafeNativeMethods.Gdip.GdipGetImageWidth(new HandleRef(this,nativeImage),out width);
 
        if (status != SafeNativeMethods.Gdip.Ok)
            throw SafeNativeMethods.Gdip.StatusException(status);
 
        return width;
    }
}

它可能会在全球范围内运行得更快。您也可以使用这样的安全版本:

unsafe
{
    byte* array = (byte*)bmpData.Scan0.ToPointer();
    byte temp;
    var max = bmp.Width * bmp.Height * 3;
    for (int x = 0; x < max; x = x + 3) {
        temp = *(array + x + 2);
        *(array + x + 2) = *(array + x);
        *(array + x) = temp;
    }
}

速度稍慢,但避免了对不安全代码的需求。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。