スレッドによる並列処理のテスト

※この記事は2017年05月24日にqiitaに投稿した内容です。

環境

Unity5.6.1f1

概要

スマホでも早くなるのかテスト 結果、自分のスマホなら早くなりました。

プログラム

using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using System.Threading;

public class TestParallelFor : MonoBehaviour
{
    [SerializeField] private Button _button = null; //切り替えボタン
    [SerializeField] private Text _text = null; //時間表示

    class ThreadParam
    {
        public Thread thread;
    //  public ManualResetEvent activeEvent;
    //  public ManualResetEvent finishEvent;
        //AutoResetEventはWaitOneでシグナル(Set)になるまで待機した後、勝手に非シグナル(Reset)になる
        public AutoResetEvent activeEvent;
        public AutoResetEvent finishEvent;
        public StringBuilder str;
        public int value;
    }

    private List<ThreadParam> _threadParams = new List<ThreadParam>();
    private bool _isParallel = false;
    private const int _threadCount = 10;
    private const int _loopCount = 1000000;

    private void Start()
    {
        _isParallel = false;
        OnButtonClick( _button );
        _button.onClick.AddListener( () => OnButtonClick( _button ) );

        for( int i = 0; i < _threadCount; i++ )
        {
            var param = new ThreadParam();
            param.thread = new Thread( ThreadFunc );
        //  param.activeEvent = new ManualResetEvent( false );  //寝かせておく
        //  param.finishEvent = new ManualResetEvent( false );  //寝かせておく
            param.activeEvent = new AutoResetEvent( false );    //寝かせておく
            param.finishEvent = new AutoResetEvent( false );    //寝かせておく
            param.str = new StringBuilder( 64 );
            _threadParams.Add( param );

            param.thread.IsBackground = true;
            param.thread.Start( param );
        }
    }

    private void OnApplicationQuit()
    {
        OnDestroy();
    }

    private void OnDestroy()
    {
        for( int i = 0; i < _threadParams.Count; i++ )
        {
            var param = _threadParams[ i ];
            if( param.thread == null )
                continue;
            param.thread.Abort();
        }
        _threadParams.Clear();
    }

    private void OnButtonClick( Button button )
    {
        _isParallel = ( _isParallel == true ) ? false : true;

        button.GetComponentInChildren<Text>().text = ( _isParallel == true ) ? "Change Single" : "Change Parallel";
    }

    private void Update()
    {
        Debug.Log( "Start" );
        var startTime = Time.realtimeSinceStartup;
        if( _isParallel == true )
            Parallel();
        else
            Single();
        var elapsedTime = Time.realtimeSinceStartup - startTime;
        _text.text += ":" + elapsedTime.ToString();
        Debug.Log( "Finish" );
    }

    private void Single()
    {
        int value = 0;
        for( int i = 0; i < _threadParams.Count; i++ )
        {
            var param = _threadParams[ i ];
            Task( param );
            value += param.value;
        }
        _text.text = ( value / _loopCount / _threadCount ).ToString();
    }

    private void Parallel()
    {
        //parallel
        for( int i = 0; i < _threadParams.Count; i++ )
        {
            var param = _threadParams[ i ];
            param.activeEvent.Set();
        }
        //finish sync
        int value = 0;
        for( int i = 0; i < _threadParams.Count; i++ )
        {
            var param = _threadParams[ i ];
            param.finishEvent.WaitOne();
        //  param.finishEvent.Reset();
            value += param.value;
        }
        _text.text = ( value / _loopCount ).ToString();
    }

    private void ThreadFunc( object obj )
    {
        var param = (ThreadParam)obj;
        while( true )
        {
            param.activeEvent.WaitOne();
        //  param.activeEvent.Reset();

            Task( param );

            param.finishEvent.Set();
        }
    }

    private void Task( ThreadParam param )
    {
        param.value = 0;
        for( int i = 0; i < _loopCount; i++ )
        {
            param.value++;
        }
        param.str.Length = 0;//.Remove( 0, param.str.Length );
        param.str.Append( "Task:" ).Append( param.thread.ManagedThreadId );
    //  Debug.Log( param.str.ToString() );
    }
}