使用 x86 汇编实现 C# 的快速内存拷贝

大家好,我是Oleksandr Karpov,这个是我第一次发表文章,希望大家喜欢。

在这我将为大家展示和介绍怎么样在C#和.NET下使用汇编秒速拷贝数据,在我是实例里面我用了一运用程序创建了一段视频,里面包含图片,视频和声音。

当然如果你也需要在C#使用汇编的情况,这方法给你提供一个快速简单的解决途径。

背景

理解本文的内容, 最好具备以下知识: 汇编语言, 内存对齐, c#, windows 和 .net 高级技巧(advanced techniques).
 要提高数据复制(copy-past )的速度, 我们需要将内存地址按 16 个字节对齐. 否则, 速度不会有明显的改变. (我的例子大概快 1.02 倍 )
 
Pentium III+ (KNI/MMX2) 和 AMD Athlon (AMD EMMX) 这两种处理器都支持本文代码用到 SSE 指令集.

我用配置为: Pentium Dual-Core E5800 3.2GHz, 4GB RAM 双通道内存的计算机做测试, 16 个字节内存对齐的速度要比标准方式快 1.5 倍, 而非内存对齐方式的速度几乎没有变化(1.02倍).

使用代码

这是一个完整的演示测试,向你展示了性能测试以及如何使用。

FastMemCopy   类包含了用于快速内存拷贝逻辑的所有内容。

首先你需要创建一个默认的Windows Forms应用程序工程,在窗体上放两个按钮,一个PictureBox 控件,因为我们将用图片来测试。

声明几个字段先:

string bitmapPath;
Bitmap bmp, bmp2;
BitmapData bmpd, bmpd2;
byte[] buffer = null;

现在创建两个方法用来处理按钮的点击事件。

标准方法如下:

private void btnStandard_Click(object sender, EventArgs e)
{
        using (OpenFileDialog ofd = new OpenFileDialog())
        {
            if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
 
            bitmapPath = ofd.FileName;
        }
 
  //open a selected image and create an empty image with the same size
        OpenImage();
 
  //unlock for read and write images
        UnlockBitmap();
 
  //copy data from one image to another by standard method
        CopyImage();
 
  //lock images to be able to see them
        LockBitmap();
 
  //lets see what we have
        pictureBox1.Image = bmp2;
}

快速方法如下:

private void btnFast_Click(object sender, EventArgs e)
{
  using (OpenFileDialog ofd = new OpenFileDialog())
        {
            if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            bitmapPath = ofd.FileName;
        }
 
  //open a selected image and create an empty image with the same size
        OpenImage();
 
  //unlock for read and write images
        UnlockBitmap();
 
  //copy data from one image to another with our fast method
        FastCopyImage();
 
  //lock images to be able to see them
        LockBitmap();
 
  //lets see what we have
        pictureBox1.Image = bmp2;
}

好的,现在我们有按钮并且也有了事件处理,下面来实现打开图片、锁定、解锁它们的方法,以及标准拷贝方法:

打开一个图片:

void OpenImage()
{
  pictureBox1.Image = null;
  buffer = null;
  if (bmp != null)
  {
    bmp.Dispose();
    bmp = null;
  }
  if (bmp2 != null)
  {
    bmp2.Dispose();
    bmp2 = null;
  }
  GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
 
  bmp = (Bitmap)Bitmap.FromFile(bitmapPath);
 
  buffer = new byte[bmp.Width * 4 * bmp.Height];
  bmp2 = new Bitmap(bmp.Width, bmp.Height, bmp.Width * 4, PixelFormat.Format32bppArgb,
    Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0));
}

锁定和解锁位图:

void UnlockBitmap()
{
  bmpd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,
    PixelFormat.Format32bppArgb);
  bmpd2 = bmp2.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,
    PixelFormat.Format32bppArgb);
}
 
void LockBitmap()
{
  bmp.UnlockBits(bmpd);
  bmp2.UnlockBits(bmpd2);
}

从一个图片拷贝数据到另一个图片,并且显示测得的时间:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/45be6330e9b5e25282ad563da1cad68a.html