为什么数组初始化会减慢多线程?

时间:2016-05-30 17:26:41

标签: c# arrays multithreading unity3d hash

我尝试将线程支持添加到散列多维坐标的方法中。这里的长期目标是包含LineHeightSpan哈希值,但只要在FNV1A方法中初始化坐标数组就会出现减速。

我迭代了一百万次,对于一个线程,我得到了约300毫秒的秒表时间。对于8个线程,时间碰到~6000ms。

这是一个错误的分享问题吗?如果是这样,我担心的是散列会因填充和偏移注入阵列而恶化。任何有关使用本地阵列执行此操作的帮助将不胜感激。非常感谢!

Hash

1 个答案:

答案 0 :(得分:1)

内存分配似乎是这里的问题。我创建了两个数组static,然后在函数外部分配了一次内存。每次访问它时,locked都是数组,以确保另一个Thread没有访问它们。即使在使用lock关键字后,也不确定我的代码有多安全。

无相关问题

在主while (iterationsCompleted < iterations);上调用

Thread。这并不好,每次调用Multithread()并且仍在运行时,它都会暂时冻结Unity。我在其上添加了另一个Thread,它将启动whenMultithread()。因此,现在正在从这个新的Thread而不是主Thread调用其他线程。

在我的电脑上测试结果

原始代码

1 thread = 454.3515
8 threads = 655.008

修改后的代码

1 thread = 296.794
8 threads = 107.8898

8个帖子的效果提升超过6x。 所有测试都是在代码中包含return FNV1A(data);并且代码中已删除/注释return 0;的情况下完成的。

现在,您的工作是确保您获得的数据/哈希符合您的预期。

public class Foo : MonoBehaviour
{
    #region Fields
    private readonly int iterations = 1000000;
    private readonly int threadNum = 1;
    private int iterationsCompleted = 0;
    #endregion

    void Start()
    {
        Multithread();
    }

    private void Multithread()
    {
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();

        //Start new Thread so that while (iterationsCompleted < iterations) ; will not run in the main loop
        new Thread(() =>
          {

              for (int i = 0; i < threadNum; i++)
              {
                  Hash hash = new Hash();
                  new Thread(() =>
                  {
                      while (Interlocked.Increment(ref iterationsCompleted) < iterations)
                      {
                          hash.Get(0, 0, 0);
                      }
                      UnityEngine.Debug.Log("Finished thread");
                  }).Start();
              }
              while (iterationsCompleted < iterations) ;
              stopWatch.Stop();
              UnityEngine.Debug.Log(stopWatch.Elapsed.TotalMilliseconds);

          }).Start();
    }
}

public class Hash
{
    #region Fields
    // FNV parameters can be found at http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
    private const uint _FNVPrime = 16777619;
    private const uint _FNVOffset = 2166136261;
    private const uint _FNVMask8 = (1 << 8) - 1;
    private const int FIXEDSIZE = 3;
    private readonly System.Object locker = new System.Object();
    #endregion

    #region Class Methods
    private static uint FNV1A(uint[] data)
    {
        uint hash = _FNVOffset;

        Buffer.BlockCopy(data, 0, byteArray, 0, byteArray.Length);

        for (int i = 0; i < byteArray.Length; i++)
        {
            hash = hash ^ byteArray[i];
            hash = hash * _FNVPrime;
        }
        return hash;
    }

    static byte[] byteArray = new byte[FIXEDSIZE * sizeof(UInt32)];
    static uint[] data = new uint[3] { (uint)0, (uint)0, 0 };

    public uint Get(int x, int y, uint seed)
    {
        lock (locker)
        {
            data[0] = (uint)x;
            data[1] = (uint)y;
            data[2] = (uint)seed;
            return FNV1A(data);
        }
    }
    #endregion
}