2012-05-10 36 views
9

Tôi đang tạo trò chơi bằng cách sử dụng khung công tác XNA, vì vậy tôi sử dụng rất nhiều chức năng hoạt động trên vectơ. (đặc biệt là Vector2 (cấu trúc 64bit)). Điều làm phiền tôi là hầu hết các phương thức được định nghĩa với tham số ref và out. Dưới đây là ví dụ:Lợi ích của việc sử dụng out/ref so với return là gì?

void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result) 

có vẻ hơi lạ. Ngoài ra còn có một Min đó là rõ ràng hơn

public static Vector2 Min(Vector2 value1, Vector2 value2); 

Về cơ bản, hầu hết tất cả các chức năng có quá tải với ref s và out s. Tương tự, khác APIs.

Lợi ích của thiết kế này là gì? XNA được tối ưu hóa cho hiệu suất, nó có thể là một kết quả? Nói, Quaternion yêu cầu 128b, nơi đi qua ref ít hơn.

EDIT:

Đây là một mã kiểm tra:

public class Game1 : Microsoft.Xna.Framework.Game 
{ 
    GraphicsDeviceManager graphics; 
    SpriteBatch spriteBatch; 

    private Vector2 vec1 = new Vector2(1, 2); 
    private Vector2 vec2 = new Vector2(2, 3); 
    private Vector2 min; 
    private string timeRefOut1; 
    private string timeRefOut2; 
    private SpriteFont font; 

    public Game1() 
    { 
     graphics = new GraphicsDeviceManager(this); 
     Content.RootDirectory = "Content"; 

     refOut1(); 
     refOut2(); 
    } 

    private Vector2 refOut1() 
    { 
     Vector2 min = Vector2.Min(vec1, vec2); 
     return min; 
    } 

    private Vector2 refOut2() 
    { 
     Vector2.Min(ref vec1, ref vec2, out min); 
     return min; 
    } 

    protected override void Initialize() 
    { 
     const int len = 100000000; 
     Stopwatch stopWatch = new Stopwatch(); 
     stopWatch.Start(); 
     for (int i = 0; i < len; i++) 
     { 
      refOut1(); 
     } 
     stopWatch.Stop(); 

     timeRefOut1 = stopWatch.ElapsedMilliseconds.ToString(); 

     stopWatch.Reset(); 
     stopWatch.Start(); 
     for (int i = 0; i < len; i++) 
     { 
      refOut2(); 
     } 
     stopWatch.Stop(); 

     timeRefOut2 = stopWatch.ElapsedMilliseconds.ToString(); 

     base.Initialize(); 
    } 

    protected override void LoadContent() 
    { 
     spriteBatch = new SpriteBatch(GraphicsDevice); 
     font = Content.Load<SpriteFont>("SpriteFont1"); 
    } 

    protected override void Update(GameTime gameTime) 
    { 
     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
      this.Exit(); 

     base.Update(gameTime); 
    } 

    protected override void Draw(GameTime gameTime) 
    { 
     GraphicsDevice.Clear(Color.CornflowerBlue); 

     spriteBatch.Begin(); 
     spriteBatch.DrawString(font, timeRefOut1, new Vector2(200, 200), Color.White); 
     spriteBatch.DrawString(font, timeRefOut2, new Vector2(200, 300), Color.White); 
     spriteBatch.End(); 

     // TODO: Add your drawing code here 

     base.Draw(gameTime); 
    } 
} 

Kết quả:

  • refOut1 2200
  • refOut2 1400

Win 7 64bit,. Net 4. XNA 4.0

Ngoài ra IL đang

.method public hidebysig static void Min(valuetype Microsoft.Xna.Framework.Vector2& value1, 
              valuetype Microsoft.Xna.Framework.Vector2& value2, 
              [out] valuetype Microsoft.Xna.Framework.Vector2& result) cil managed 
{ 
    // Code size  69 (0x45) 
    .maxstack 3 
    IL_0000: ldarg.2 
    IL_0001: ldarg.0 
    IL_0002: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0007: ldarg.1 
    IL_0008: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_000d: blt.s  IL_0017 
    IL_000f: ldarg.1 
    IL_0010: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0015: br.s  IL_001d 
    IL_0017: ldarg.0 
    IL_0018: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_001d: stfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0022: ldarg.2 
    IL_0023: ldarg.0 
    IL_0024: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0029: ldarg.1 
    IL_002a: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_002f: blt.s  IL_0039 
    IL_0031: ldarg.1 
    IL_0032: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0037: br.s  IL_003f 
    IL_0039: ldarg.0 
    IL_003a: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_003f: stfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0044: ret 
} // end of method Vector2::Min 

.method public hidebysig static valuetype Microsoft.Xna.Framework.Vector2 
     Min(valuetype Microsoft.Xna.Framework.Vector2 value1, 
      valuetype Microsoft.Xna.Framework.Vector2 value2) cil managed 
{ 
    // Code size  80 (0x50) 
    .maxstack 3 
    .locals init (valuetype Microsoft.Xna.Framework.Vector2 V_0) 
    IL_0000: ldloca.s V_0 
    IL_0002: ldarga.s value1 
    IL_0004: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0009: ldarga.s value2 
    IL_000b: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0010: blt.s  IL_001b 
    IL_0012: ldarga.s value2 
    IL_0014: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0019: br.s  IL_0022 
    IL_001b: ldarga.s value1 
    IL_001d: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0022: stfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0027: ldloca.s V_0 
    IL_0029: ldarga.s value1 
    IL_002b: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0030: ldarga.s value2 
    IL_0032: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0037: blt.s  IL_0042 
    IL_0039: ldarga.s value2 
    IL_003b: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0040: br.s  IL_0049 
    IL_0042: ldarga.s value1 
    IL_0044: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0049: stfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_004e: ldloc.0 
    IL_004f: ret 
} // end of method Vector2::Min 

vẻ overhead là do tạm Vector. Ngoài ra tôi đã cố gắng 1GHz WP 7,5 thiết bị:

Số ve cho một bậc số nhỏ hơn của lần lặp lại.

+1

Tôi đoán câu hỏi * thực * là, "không nên .NET làm RVO?" – Mehrdad

Trả lời

7

Vector2 là một cấu trúc, có nghĩa là khi nó được trả về dưới dạng giá trị, một bản sao được trả về, thay vì trả lại tham chiếu đến cấu trúc hiện có. Bằng cách sử dụng tham số ref/out, bạn có thể tránh bản sao này để Vector được tạo trong phương thức Min là vectơ chính xác trong biến số result của bạn. Đây là một trong những tối ưu hóa vi mô thông thường sẽ không được khuyến khích, nhưng trong thế giới trò chơi nó được thực hiện thường xuyên đủ, và trong môi trường nơi hiệu suất đủ quan trọng, nó có giá trị tùy chọn ít có thể đọc được hơn.

+0

Gán một loại giá trị cho tham số out/ref cũng là "sao chép" giá trị từ biến cục bộ vào tham số. –

+2

@PeterRitchie Toàn bộ điểm sẽ là tham số out/ref sẽ được sử dụng như biến cục bộ trong toàn bộ phương thức sao cho bạn không có bản sao từ biến cục bộ đến tham số out/ref. Nếu không, có, bạn sẽ thực hiện một bản sao bổ sung và nó sẽ đánh bại mục đích. – Servy

+1

Bạn vẫn gán giá trị từ một biến này sang biến khác (tham số). Nhiệm vụ là một hoạt động "sao chép"; miễn là bạn chỉ định một loại giá trị cho một biến (bất kể loại), bạn đang "sao chép" giá trị. –

3

Một sự khác biệt trên hiệu suất hoạt động được Servy đề cập là khả năng có nhiều giá trị "trả về" thay vì trả về giá trị thông thường, bạn liệt kê chúng dưới dạng tham số ref/var.

+2

Đó là suy nghĩ đầu tiên của tôi, nhưng họ chỉ trả về 1 giá trị. –

+0

@ lukas - trong trường hợp này, vâng, tôi đã viết cho trường hợp chung :) – Attila

Các vấn đề liên quan