为什么Marshal.Copy比不安全更快? [英] Why Marshal.Copy is faster than unsafe?

查看:75
本文介绍了为什么Marshal.Copy比不安全更快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在读,不安全比Marshal更快。复制,

但接下来的2个代码显示相反的结果:



较慢:

 不安全 
{
for int i = 0 ; i < w * h * 3 ; i ++)
((byte *)data2.Scan0)[i] = .bytes-α] [I];
}



更快:

 Marshal.Copy(bytes [alpha], 0 ,data2.Scan0,bytes [。] .Length); 





完整代码:

 使用系统; 
使用 System.Collections.Generic;
使用 System.ComponentModel;
使用 System.Data;
使用 System.Drawing;
使用 System.Linq;
使用 System.Text;
使用 System.Windows.Forms;
使用 System.Drawing.Drawing2D;
使用 System.Drawing.Imaging;
使用 System.Runtime.InteropServices;

命名空间 _123
{
public partial class Form1:Form
{
public Form1()
{
InitializeComponent();

this .DoubleBuffered = true ;

Create_Animation();
this .Paint + = Draw;

timer1 = new Timer();
timer1.Interval = 1 ;
timer1.Enabled = true ;
timer1.Tick + = Draw_Animation;
}

int w;
int h;

字节 [] []字节;

private void Create_Animation()
{
// w = System.Windows.Forms.Screen.GetBounds(this).Width;
// h = System.Windows.Forms.Screen.GetBounds(this).Height;

w = 1000 ;
h = 1000 ;

bitmap1 = new 位图(w,h);
bytes = new 字节 [ 256 ] [];

图形g1 = Graphics.FromImage(bitmap1);

for int alpha = 0 ; alpha < 256 ; alpha ++)
{
g1.Clear(Color.FromArgb(alpha, 255 255 255 ));

bytes [alpha] = new 字节 [w * h * 3 ];

BitmapData data1 = bitmap1.LockBits( new 矩形( 0 0 ,w,h),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb);
Marshal.Copy(data1.Scan0,bytes [alpha], 0 ,bytes [。] .Length);
bitmap1.UnlockBits(data1);
}

bitmap2 = new 位图(w,h);
g2 = Graphics.FromImage(bitmap2);
}

位图bitmap1;
位图bitmap2;
图形g2;

定时器timer1 = Timer();

private void 绘制( object sender,PaintEventArgs e)
{
e.Graphics.DrawImage(bitmap2, 0 0 );
}

int alpha = 1 ;
int plus = 50 ;

private void Draw_Animation( object sender,EventArgs e)
{
BitmapData data2 = bitmap2.LockBits( new Rectangle( 0 0 ,w,h),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb);
不安全
{
for int i = 0 ; i < w * h * 3 ; i ++)
((byte *)data2.Scan0)[i] = this .bytes -α] [I];
}

// Marshal.Copy(bytes [alpha],0, data2.Scan0,bytes [。] .Length);

bitmap2.UnlockBits(data2);

.alpha + = plus;
if (alpha > 255
{
alpha = 255 ;
plus * = -1;
}
if (alpha < 0
{
alpha = 0 ;
plus * = -1;
}

this .Invalidate();
}
}
}

解决方案

Marshal.Copy Buffer.BlockCopy 使用框架的内核和c ++代码来移动比你的更高级别的c#代码更快的字节。

问题没有正确提出。 不安全不能更快或更慢,因为 unsafe 不是导致生成某些代码占用任何CPU时间的语句。它只是允许您执行指针操作的语句。所以,一切都取决于你对指针操作的处理方式。实际表现取决于很多因素。



使用 Marshal.Copy 。它的实现可以优化,例如,不是因为这是C ++,而是因为它可以使用一些初步创建的非托管代码,以某种方式进行优化。请记住,IL基于JIT( http://en.wikipedia.org/wiki/Just-in-time_compilation [ ^ ])。当你使用 unsafe 时,你仍然使用托管对象,应该固定( LockBits 实际上是这样做的),等等一。很难说它如何转化为整体表现。如果你设法构建一些其他代码示例,你的指针算法比其他方法更快,我会不会感到惊讶。



顺便说一下,如果你这样做的话你的性能实验,排除JIT编译所花费的时间很重要。怎么样? JIT通常在每个方法的基础上工作。因此,在测量时序之前,您需要确保每个定时方法至少在调用之前调用过一次,然后调用所有其他方法。使用 System.Diagnostics.StopWatch 进行计时。



-SA

I have been reading that unsafe is faster than Marshal.Copy,
but the next 2 codes show converse results:

Slower:

unsafe
            {
                for (int i = 0; i < w * h * 3; i++)
                    ((byte*)data2.Scan0)[i] = this.bytes[alpha][i];
            }


Faster:

Marshal.Copy(bytes[alpha], 0, data2.Scan0, bytes[alpha].Length);



Full code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace _123
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.DoubleBuffered = true;

            Create_Animation();
            this.Paint += Draw;

            timer1 = new Timer();
            timer1.Interval = 1;
            timer1.Enabled = true;
            timer1.Tick += Draw_Animation;
        }

        int w;
        int h;

        Byte[][] bytes;

        private void Create_Animation()
        {
            //w = System.Windows.Forms.Screen.GetBounds(this).Width;
            //h = System.Windows.Forms.Screen.GetBounds(this).Height;
            
            w = 1000;
            h = 1000;

            bitmap1 = new Bitmap(w, h);
            bytes = new Byte[256][];

            Graphics g1 = Graphics.FromImage(bitmap1);

            for (int alpha = 0; alpha < 256; alpha++)
            {
                g1.Clear(Color.FromArgb(alpha, 255, 255, 255));

                bytes[alpha] = new Byte[w * h * 3];

                BitmapData data1 = bitmap1.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                Marshal.Copy(data1.Scan0, bytes[alpha], 0, bytes[alpha].Length);
                bitmap1.UnlockBits(data1);
            }

            bitmap2 = new Bitmap(w, h);
            g2 = Graphics.FromImage(bitmap2);
        }

        Bitmap bitmap1;
        Bitmap bitmap2;
        Graphics g2;

        Timer timer1 = new Timer();

        private void Draw(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImage(bitmap2, 0, 0);
        }

        int alpha = 1;
        int plus = 50;

        private void Draw_Animation(object sender, EventArgs e)
        {
            BitmapData data2 = bitmap2.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            unsafe
            {
                for (int i = 0; i < w * h * 3; i++)
                    ((byte*)data2.Scan0)[i] = this.bytes[alpha][i];
            }

            //Marshal.Copy(bytes[alpha], 0, data2.Scan0, bytes[alpha].Length);

            bitmap2.UnlockBits(data2);

            this.alpha += plus;
            if (alpha > 255)
            {
                alpha = 255;
                plus *= -1;
            }
            if (alpha < 0)
            {
                alpha = 0;
                plus *= -1;
            }

            this.Invalidate();
        }
    }
}

解决方案

Marshal.Copy and Buffer.BlockCopy use the framework's kernel and c++ code to move the bytes around which is going to be faster than your higher level c# code.


The question is not correctly posed. "Unsafe" cannot be faster or slower, because unsafe is not a statement which cause generation of some code taking any CPU time. It's merely the statement which allows you to do the pointer operations. So, everything depends on what you do with your pointer operations. The actual performance depends on many factors.

Take the use of Marshal.Copy. Its implementation can be optimized, for example, not because this is C++, but because it can use some preliminary created unmanaged code, somehow optimized. Remember that IL is based on JIT (http://en.wikipedia.org/wiki/Just-in-time_compilation[^]). When you use unsafe, you still use managed objects, which should be pinned (LockBits actually does that), and so one. It's hard to say how it translates into overall performance. I would not be much surprised if you manage to build some other code sample where your pointer arithmetic turns out faster than some other approach.

By the way, if you do your experiment with performance, it's important to exclude the time taken by JIT compilation. How? JIT normally works on per-method basis. So, before measuring timing, you need to make sure that every timed method was already called before at least once, with all the other methods it calls. Use System.Diagnostics.StopWatch for timing.

—SA


这篇关于为什么Marshal.Copy比不安全更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆