2013-05-20 2 views
8

아래는 WPF에서 Conway의 Game of Life를 구현 한 (매우 순진한) 예입니다. 뒤에Brushes.White는 그래픽 데모 속도를 늦춤니다.

<Window x:Class="wpf_conway_life_2013_05_19.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="500" Width="500"> 
    <Grid> 
     <Canvas Name="canvas" 
      Width="auto" 
      Height="auto" 
      HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch"> 
     </Canvas> 
    </Grid> 
</Window> 

코드 : 내가 함께 new SolidColorBrush(new Color())를 교체 할 경우

enter image description here

: 여기

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 
using System.Windows.Shapes; 
using System.Windows.Threading; 

namespace wpf_conway_life_2013_05_19 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      var random = new Random(); 

      var data = new int[100, 100]; 

      var dataB = new int[100, 100]; 

      Func<int, int, int> at = (x, y) => 
       { 
        if (x < 0) x = 100 + x; 
        if (x >= 100) x = x % 100; 
        if (y < 0) y = 100 + y; 
        if (y >= 100) y = y % 100; 

        return data[x, y]; 
       }; 

      for (var x = 0; x < 100; x++) 
       for (var y = 0; y < 100; y++) 
        data[x, y] = random.Next(2); 

      var rectangles = new Rectangle[100, 100]; 

      for (var x = 0; x < 100; x++) 
       for (var y = 0; y < 100; y++) 
       { 
        rectangles[x, y] = new Rectangle(); 

        canvas.Children.Add(rectangles[x, y]); 
       } 

      canvas.SizeChanged += (s, e) => 
       { 
        for (var x = 0; x < 100; x++) 
        { 
         for (var y = 0; y < 100; y++) 
         { 
          rectangles[x, y].Width = canvas.ActualWidth/100; 
          rectangles[x, y].Height = canvas.ActualHeight/100; 

          Canvas.SetLeft(rectangles[x, y], (canvas.ActualWidth/100) * x); 
          Canvas.SetTop(rectangles[x, y], (canvas.ActualHeight/100) * y); 
         } 
        } 
       }; 

      Action macroStep =() => 
       { 
        dataB = new int[100, 100]; 

        for (var x = 0; x < 100; x++) 
        { 
         for (var y = 0; y < 100; y++) 
         { 
          var neighbors = 0; 

          for (var i = -1; i <= 1; i++) 
           for (var j = -1; j <= 1; j++) 
            if (i == 0 && j == 0) 
             continue; 
            else 
             neighbors += at(x + i, y + j); 

          dataB[x, y] = data[x, y]; 

          if (neighbors < 2) dataB[x, y] = 0; 
          if (neighbors == 3) dataB[x, y] = 1; 
          if (neighbors > 3) dataB[x, y] = 0; 

          rectangles[x, y].Fill = dataB[x, y] == 0 ? new SolidColorBrush(new Color()) : Brushes.Black; 
         } 
        } 

        data = dataB; 
       }; 

      var timer = new DispatcherTimer(); 

      timer.Tick += (s, e) => macroStep(); 

      timer.Start(); 
     } 
    } 
} 

것 같습니다 무엇 그것은

XAML은 ... 그냥 데모입니다 Brushes.White 프로그램이 훨씬 느리게 실행됩니다. 왜?

2010 Express를 사용하여 Windows 7 64 비트에서 테스트하고 있습니다.

+2

렌더링 또는 검색 문제인지 여부를 좁히려면 루프 외부의 브러시에 대한 캐시 된 참조를 유지하고 'Brushes.White'대신 해당 참조를 사용하면 속도가 영향을 받습니까? 시스템 브러쉬는'Dictionary '에 캐싱됩니다.이 항목은 항목을 검색 할 때마다 잠 가야합니다. –

+2

'Brushes.Transparent'와 같은 동작을합니까? – Rachel

+1

@SimonMcKenzie 좋은 제안. 그러나, 나는 그것을 시도하고 아무런 차이가 없습니다. (그런데, MapSnap 축하, 아주 멋진 WP7 앱!) – dharmatech

답변

1

new Color()은 0의 알파 값을 가지므로 WPF는 완전히 투명하기 때문에 렌더링 할 필요가 없습니다. 반면에 흰색의 알파는 255이므로 렌더링해야 할 완전히 흰색의 흰색을 의미합니다 .

+0

좋은 제안 Jaska. 그러나 새로운 ColorColorBrush (새로운 Color() {R = 255, G = 255, B = 255, A = 255})'와 같이 느리게 진행됩니다. 그러나 그렇지 않습니다. – dharmatech

0

Brushes.White을 사용하는 경우 특별한 것은 없습니다.

macroStep 이벤트 처리기 외부에서 자체 로컬 브러시를 정의한 다음 고정하면 Brushes.White와 완전히 동일하게 작동합니다. 당신이 그것을 먼저 동결하지 않으면, 그것은 훨씬 더 멀리 행동합니다.

최상의 성능은 매끄럽게하기 전에 macrostep 호출이 시작될 때마다 한 번 브러시를 만든 다음 멈추는 것이 가장 좋습니다. 가장 안쪽의 루프 안에 새로운 브러쉬를 만들면 상당한 속도 저하입니다.

또한 잘못된 동작 코드의 타이머 간격을 늘리면 실제로 성능 문제가 해결됩니다. 내 생각 엔 매번 렌더링이 끝난 후에는 배경 스레드에서 발생하는 리소스 정리 작업이 브러시의 내부 구조와 연결되어 있지만, 주변에서 돌아 다니기 때문에 정리 작업을 수행 할 수 없다는 것입니다. 다음 반복에서 브러시를 사용합니다. 이를 설명하기 위해 브러쉬의 풀을 생성하고 다른 브러시 때마다 사용 : 1로 브러시의 수를 설정하면

SolidColorBrush[] brushes = new SolidColorBrush[2]; 
for (int i = 0; i < brushes.Length; i++) 
{ 
    var brush = new SolidColorBrush(new Color()); 
    brush.Freeze(); 
    brushes[i] = brush; 
} 
int brushIx = 0; 

Action macroStep =() => 
{ 
    dataB = new int[100, 100]; 
    var brush = brushes[brushIx++ % brushes.Length]; 
... 
    rectangles[x, y].Fill = dataB[x, y] == 0 
     ? brush 
     : Brushes.Black; 
    data = dataB; 
}; 

, 이것은 Brushes.White를 사용하는 것과 동일한 동작을 줄 것이다. 그러나 2 개 이상으로 설정하면 예상 한 성능을 얻을 수 있습니다.

+0

브라이스 제안에 감사드립니다. 이 코드를 시스템에서 테스트하여 다양한 변형을 비교 했습니까? 내 시스템에서 내부 루프에 새로운 브러시를 생성하는 것은 브러시를 생성하거나 동결시키는 것보다 더 빠르고,'macroStep'의 바깥 쪽이나 안쪽에 있습니다. 매우 기괴합니다. – dharmatech

+1

@dharmatech, 저는 방금 세 가지 경우 모두를 테스트했습니다. 원본을 "new SolidColorBrush (new Color())"로 브라이스가 제안한 것으로, 얼린 브러시 배열과 다시 브러쉬로 배열 한 것입니다. 내 컴퓨터에서 가장 빠른 것은 두 번째 것이 었습니다 - 브러시 어레이 (여기서는 놀랄 일이 아닙니다). 가장 느린 것이 마지막이었습니다 - Brushes. White. 그리고 원래 "새로운 SolidColorBrush (new Color())"가 중간에있는 경우가있었습니다. 눈에 띄기는했지만 승자와 두 번째 선수 사이에 그 차이를 더하는 것은 가치가있을 수 있지만 두 번째와 세 번째 사이에는 그다지 차이가 ​​없습니다. – Sevenate