前準備:Bitmapの排除
そんなわけで高速化の戦略は「計算コビト(内の計算ルーチン)を増員し、各コビトを並行動作させる」こと。シングルコア機ではマルチスレッドにしたところで一つのスレッドしか動けないので高速化は望めませんが、マルチコア機なら少しは速くなってくれることでしょう。幸いにも絵描きコビトは数百msごとの描画(Bitmapから画面への転写)が主な仕事であり、それが終わればつぎの描画まではほぼ休止状態のはず。そうであれば複数の計算コビトが働く余地があるでしょうから。
では前準備、方眼紙:SectionPaperから排他アクセスが必要なためにコビトたちの並行動作を妨げるBitmapを抜き取り、代わりに要素数が方眼紙の幅×高さであるint配列を持たせ、計算コビトは計算結果を方眼紙内のint配列に書き込むことにします:
public class SectionPaper {
private int[,] bitmap_;
private double xa_, xb_;
private double ya_, yb_;
private int width_, height_;
public SectionPaper(int width, int height) {
width_ = width; height_ = height;
bitmap_ = new int[width_, height_];
}
public void SetScale(DComplex ul, DComplex br) {
xa_ = (br.Real() - ul.Real()) / width_;
xb_ = ul.Real();
ya_ = (br.Imag() - ul.Imag()) / height_;
yb_ = ul.Imag();
}
public int GetWidth() {
return width_;
}
public int GetHeight() {
return height_;
}
public DComplex GetPoint(int x, int y) {
return new DComplex(x*xa_+xb_, y*ya_+yb_);
}
public void SetPixel(int x, int y, int c) {
bitmap_[x,y] = c;
}
public int GetPixel(int x, int y) {
return bitmap_[x, y];
}
public void Clear() {
for (int x = 0; x < width_; ++x ) {
for (int y = 0; y < height_; ++y ) {
bitmap_[x, y] = -1;
}
}
}
}
方眼紙はもはや描画機能を持たなくなったので、描画コビト(MainForm)で面倒みなければなりません:
public partial class MainForm : Form {
private Bitmap bitmap_; // 追加
private SectionPaper paper_;
private ColorPalette palette_;
public MainForm() {
InitializeComponent();
bitmap_ = new Bitmap(pbxResult.Width, pbxResult.Height); // 追加
paper_ = new SectionPaper(pbxResult.Width, pbxResult.Height);
palette_ = new ColorPalette();
}
// SectionPaperからBtmapへの転写
private void Draw() {
int w = paper_.GetWidth();
int h = paper_.GetHeight();
lock ( bitmap_ ) {
for ( int x = 0; x < w; ++x ) {
for ( int y = 0; y < h; ++y ) {
// SectionPaper上の各点の値を色に変換してBitmapへ
bitmap_.SetPixel(x, y, palette_.GetColor(paper_.GetPixel(x, y)));
}
}
}
}
…………
// 定期的な描画
private void tmrDraw_Tick(object sender, EventArgs e) {
Draw();
Invalidate();
}
// MainFormのPaintイベント・ハンドラ
private void MainForm_Paint(object sender, PaintEventArgs e) {
lock ( bitmap_ ) {
using ( Graphics g = pbxResult.CreateGraphics() ) {
// BitmapをPictureBoxに描画
g.DrawImage(bitmap_, g.VisibleClipBounds);
}
}
}
}
……実はこれだけの変更で見違えるほどに速くなりました。1600[ms]だったのが800[ms]足らず、2倍以上のスピードアップです。計算コビトは描画コビトとは(BakgroundWorkerが用意してくれた)別のスレッドで動いていますから、両者間の排他制御が必要なくなったために二人のコビトがお互いの邪魔をせずに動いてくれたのでしょう。
