2015-12-13 96 views
-1

我想創建兩個線程,因爲我想先將循環分成兩部分。而不是for (var row = 0; row < area.Height; row++)我想爲我想要線程的每個循環制作for (var row = 0; row < area.Height/2; row++)for (var row = area.Height/2; row < area.Height; row++)。我不知道如何實現這個東西。你可以幫我嗎 ?在C#代碼中實現線程

using System; 
using System.Diagnostics; 
using System.Drawing; 
using System.Threading; 

namespace MandelbrotGenerator { 
    public class SyncImageGenerator : IImageGenerator { 
    public void GenerateImage(Area area) { 
     var sw = Stopwatch.StartNew(); 
     var bitmap = SyncImageGenerator.GenerateSyncroniously(area); 
     GenerationDone(area, bitmap, sw.Elapsed); 
    } 

    public static Bitmap GenerateSyncroniously(Area area) { 
     int maxIterations; 
     double zBorder; 
     double cReal, cImg, zReal, zImg, zNewReal, zNewImg; 

     maxIterations = Settings.DefaultSettings.MaxIterations; 
     zBorder = Settings.DefaultSettings.ZBorder * Settings.DefaultSettings.ZBorder; 

     Bitmap bitmap = new Bitmap(area.Width, area.Height); 

     for (var row = 0; row < area.Height; row++) { 
     for (var col = 0; col < area.Width; col++) { 
      var pixelWidth = (area.MaxReal - area.MinReal)/area.Width; 
      cReal = area.MinReal + col * pixelWidth; 
      var pixelHeight = (area.MaxImg - area.MinImg)/area.Height; 
      cImg = area.MinImg + row * pixelHeight; 
      zReal = 0.0; 
      zImg = 0.0; 
      var iter = 0; 
      while (zReal*zReal+zImg*zImg<zBorder && iter<maxIterations) { 
      zNewReal = zReal * zReal - zImg * zImg; 
      zNewImg = zImg * zReal + zReal * zImg; 
      zNewReal = zNewReal + cReal; 
      zNewImg = zNewImg + cImg; 
      zReal = zNewReal; 
      zImg = zNewImg; 
      iter++; 
      } 
      bitmap.SetPixel(col, row, ColorSchema.GetColor(iter)); 
     } 
     } 

     return bitmap; 
    } 
    public event EventHandler<EventArgs<Tuple<Area, Bitmap, TimeSpan>>> ImageGenerated; 
    private void GenerationDone(Area area, Bitmap bitmap, TimeSpan time) { 
     if (ImageGenerated != null) { 
     ImageGenerated(this, new EventArgs<Tuple<Area, Bitmap, TimeSpan>>(Tuple.Create(area, bitmap, time))); 
     } 
    } 
    } 
} 

其實,我不知道如何使用所有這些變量以及如何使用2個線程共享所有這些變量。

+1

首先,請參閱http://www.codeproject.com/Articles/406045/Why-the-use-of-GetPixel-and-SetPixel-is-so-ineffic,http://www.codeproject.com/文章/ 617613/Fast-Pixel-Operations-in-NET-With-and-Without-unsa,以及http://stackoverflow.com/questions/24701703/c-sharp-faster-alternatives-to-setpixel-and-getpixel -for-bitmaps-for-windows-f – user2864740

+0

感謝這些。你能建議我怎麼能輕鬆地將這個循環分割爲線程? – Giga

+0

正如你所描述的,但實際上*使用*線程。網上有很多線程教程。創建/啓動提供相應域信息的線程(或者使用'Parallel.ForEach',注意,與手動Thread impl不同,它可以決定實際使用多少個線程),然後等待完成。無論如何,僅僅通過避免SetPixel就可能會有更好的性能提升。 – user2864740

回答

-1

當有足夠多的抽象可供選擇時,不要直接使用線程。 TPL是其中之一,但我更喜歡微軟的Reactive Framework(NuGet「Rx-Main」)。有了它,你可以這樣做:

public static IObservable<Bitmap> GenerateAsynchronously(Area area) 
{ 
    int maxIterations = 100; 
    double zBorder = 1.0; 

    var compute = 
     from row in Observable.Range(0, area.Height) 
     from col in Observable.Range(0, area.Width) 
     from iter in Observable.Start(() => 
     { 
      var pixelWidth = (area.MaxReal - area.MinReal)/area.Width; 
      double cReal = area.MinReal + col * pixelWidth; 
      var pixelHeight = (area.MaxImg - area.MinImg)/area.Height; 
      double cImg = area.MinImg + row * pixelHeight; 
      double zReal = 0.0; 
      double zImg = 0.0; 
      var i = 0; 
      while (zReal * zReal + zImg * zImg < zBorder && i < maxIterations) 
      { 
       double zNewReal = zReal * zReal - zImg * zImg; 
       double zNewImg = zImg * zReal + zReal * zImg; 
       zNewReal = zNewReal + cReal; 
       zNewImg = zNewImg + cImg; 
       zReal = zNewReal; 
       zImg = zNewImg; 
       i++; 
      } 
      return i; 
     }) 
     select new { row, col, iter }; 

    var query = 
     from xs in compute.ToArray() 
     from bm in Observable.Start(() => 
     { 
      Bitmap bitmap = new Bitmap(area.Width, area.Height); 
      foreach (var x in xs) 
      { 
       bitmap.SetPixel(x.col, x.row, ColorSchema.GetColor(x.iter)); 
      } 
      return bitmap; 
     }) 
     select bm; 

    return query; 
} 

您現在正在返回一個IObservable<Bitmap>,而不是Bitmap。你這樣消費:

var bitmapObservable = SyncImageGenerator.GenerateAsynchronously(area); 
    bitmapObservable 
     .Subscribe(bitmap => 
     { 
      GenerationDone(area, bitmap); 
     }); 

根本沒有必要管理線程,但你得到最大的併發性。

+0

雖然Rx對某些問題很好,但我懷疑(儘管願意接受數字),因此非常適合手頭的任務。 – user2864740

+0

非常感謝,但我只是想要一些帶有實現線程或信號量的簡單代碼來劃分for循環,以便進行某種並行化。 – Giga

+0

@ user2864740 - 你爲什麼不認爲它適合這個特定的任務? – Enigmativity