为什么Marshal.Copy比不安全更快? [英] Why Marshal.Copy is faster than unsafe?
本文介绍了为什么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
andBuffer.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, becauseunsafe
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 ofMarshal.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 useunsafe
, 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. UseSystem.Diagnostics.StopWatch
for timing.
—SA
这篇关于为什么Marshal.Copy比不安全更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文