如何在C#中模拟乘法2D数组

时间:2018-12-05 19:24:30

标签: c#

我的老师要求我通过c#中的线程将两个n×n矩阵相乘。

如何并行执行for

代码的时间复杂度如何?

此代码是否并行运行?

for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{       
    K_copy = k;
    i_copy = i;
    j_copy = j;

    myThread[k, i, j] = new Thread(() => computeMultiply(k_copy, i_copy, j_copy));
    myThread[k, i, j].Start();
}

要相乘2个矩阵(matA和matB),我们需要3个for序列方法,如下所示:

for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
matC[i,j]=matC[i,j]+matA[i,k]*matB[k,j];

考虑到我们有n ^ 3个处理器,因此我们可以并行进行乘法。因此,每个乘法都在O(1)中执行...因此我们可以降低时间复杂度。但是我没有n ^ 3个处理器,所以我必须使用线程来模拟这种情况。另一方面,我的老师想模拟SIMD系统中的运行并模拟Parallel.For的线程!

我在A,B等处理器中都有寄存器,但是我像每个线程的寄存器一样使用matP。

这是computeMultiply函数:

 static void computeMultiply(int k, int i, int j)
    {
        matP[k, i, j] = matA[i, k] * matB[k, j];            
    }

1 个答案:

答案 0 :(得分:0)

您可以这样做:

   Parallel.For(0, n, i=>
   {
        for(int j = 0; j < n; j++)
        for(int k = 0; k < n; k++)
        {       
             myThread[i, j] += matA[i,k]*matB[k,j];
        }
   });

如果您的老师想笑一点,这是Parallel.For的一些 veerery 基本实现。

public sealed class MyThreadPool : IDisposable
{
    private readonly Thread[] _threads;
    private readonly ConcurrentQueue<Action> _tasks = new ConcurrentQueue<Action>();
    private bool _enabled;
    private MyThreadPool(int count)
    {
        _enabled = true;
        _threads = new Thread[count];
        for (var i = 0; i < count; i++)
        {
            _threads[i] = new Thread(Consume);
            _threads[i].Start();
        }
    }

    public static void For(int threadCount, int from, int to, Action<int> action)
    {
        using (var pool = new MyThreadPool(threadCount))
        {
            for (int i = from; i < to; i++)
            {
                var captured = i;
                pool.EnqueueTask(() => action(captured));
            }
            pool.WaitTillCompletion();
        }
    }

    private void Consume()
    {
        while (_enabled)
        {
            Action task;
            if (_tasks.TryDequeue(out task))
            {
                try
                {
                    task();
                }
                catch
                {
                    //can log error here if you want
                }
            }
            else
            {
                Thread.Sleep(0);
            }
        }
    }

    public void EnqueueTask(Action action)
    {
        _tasks.Enqueue(action);
    }

    public void WaitTillCompletion()
    {
        while (!_tasks.IsEmpty)
            Thread.Sleep(0);
    }

    public void Dispose()
    {
        _enabled = false;
        foreach (var t in _threads)
        {
            t.Join();
        }
    }
}

像这样使用它:

   var threadCount = Environment.ProcessorCount * 4; //this is as much as modern processor can squese out of itself, larger values used only for IO loads, not for computation.
   MyThreadPool.For(threadCount, n, i=>
   {
        for(int j = 0; j < n; j++)
        for(int k = 0; k < n; k++)
        {       
             myThread[i, j] += matA[i,k]*matB[k,j];
        }
   });