【问题标题】:Multithreading matrix multiplication in C#C#中的多线程矩阵乘法
【发布时间】:2016-04-02 22:33:09
【问题描述】:

我有一个任务——编写多线程矩阵乘法。每个向量积必须在新线程中计算。(如果我们有矩阵 n x m 和 m x k 我们必须有 n x k 线程)。我还必须显示结果矩阵元素的计算顺序。我写了代码,得到了奇怪的结果——计算顺序几乎是按顺序排列的。但是我在新线程中计算每个元素,所以我必须得到结果矩阵元素的随机计算顺序。怎么了?这是我的代码。

using System;
using System.Threading;
using System.Collections.Generic;

namespace MatrixMultiplication
{
class Matrix
{
    public int Row{get; set;}
    public int Column { get; set;}
    double[,] arr;
    Matrix() { }
    public Matrix(int row,int column)
    {
        Row = row;
        Column = column;
        arr = new double[row, column];
    }
    public double[] GetColumn(int i)
    {
        double[] res=new double[Row];
        for (int j = 0; j < Row; j++)
            res[j] = arr[j, i];
        return res;
    }
    public double[] GetRow(int i)
    {
        double[] res = new double[Column];
        for (int j = 0; j < Column; j++)
            res[j] = arr[i, j];
        return res;
    }
    public double this[int i,int j]
    {
        get { return arr[i, j]; }
        set { arr[i, j] = value; }
    }
    public Matrix RandomValues()
    {
        Random rnd=new Random();
        for (int i = 0; i < Row; i++)
            for (int j = 0; j < Column; j++)
                arr[i, j] =rnd.Next(10);
        return this;
    }

    public void Print()
    {
        for(int i=0;i<Row;i++){
            for (int j = 0; j < Column; j++)
                Console.Write(arr[i,j]+" ");
            Console.WriteLine();
        }
    }

    public static Matrix operator*(Matrix a, Matrix b)
    {
        Matrix result=new Matrix(a.Row,b.Column);
        List<Thread> threads = new List<Thread>();
        for (int i = 0; i <a.Row*b.Column;i++ )
        {
            int tempi = i; 
            Thread thread = new Thread(()=>VectorMult(tempi, a, b, result));
            thread.Start();
            threads.Add(thread);
        }
        foreach (Thread t in threads)
            t.Join();
        return result;
    }

    public  static void VectorMult(int tmp, Matrix a, Matrix b,Matrix result){
        int i = tmp / b.Column;
        int j = tmp % b.Column;
        double[] x = a.GetRow(i);
        double[] y = b.GetColumn(j);
        for (int k = 0; k < x.Length; k++)
            result[i, j] += x[k] * y[k];
        Console.WriteLine("Calculate element{0}{1}", i, j);
    }
  }

  class Program
  {
     static void Main(string[] args)
     {
         int n = int.Parse(Console.ReadLine());
         int m = int.Parse(Console.ReadLine());
         int k = int.Parse(Console.ReadLine());
         Matrix A = new Matrix(n,m).RandomValues();
         Matrix B = new Matrix(m,k).RandomValues();
         A.Print();
         Console.WriteLine(new String('-',20));
         B.Print();
         Console.WriteLine(new String('-', 20));
         Matrix C = A * B;
         C.Print();
    }
  }
}

【问题讨论】:

  • 请查看您的课程作业笔记。所示代码没有演示任何同步原语的用法,这些原语很可能应该存在以获得及格分数(如果一个人真的想获得正确的结果,肯定是必须的)。

标签: c# multithreading matrix


【解决方案1】:

您所描述的是正常的 - 请参阅今天早些时候的 this post,它演示了单独线程中的进程如何并不总是以预期的顺序运行。他们可能会做很多或大部分时间,但是你会得到一些意想不到的行为。

计算是否需要按特定顺序进行,还是您只需要能够查看它们发生的顺序?

如果您正在启动新线程,则无法控制顺序。 (您已经看到了。)您也无法捕获它们完成的顺序,因为完成计算并记录结果(控制台或任何其他输出)不是原子操作。

这可能发生:

  1. 计算 A 完成
  2. 计算 B 完成
  3. 计算 B 被记录
  4. 计算 A 被记录

当操作必须以特定顺序发生时,多线程并不是很好。

您可以在计算结果完成后将其插入ConcurrentQueue,并且顺序将大部分正确。

【讨论】:

  • 我需要查看计算线程的顺序。我在没有多线程的程序中得到几乎相等的输入(我在屏幕上打印结果矩阵元素的编号)。但我认为结果矩阵的元素应该按随机顺序计算。
  • 为了确保我理解 - 你是说计算的顺序可能是随机的还是你想让它随机?
  • 我想让它随机。但是我认为当我在不同线程中计算结果矩阵的元素时,默认情况下计算顺序必须是随机的。我错了吗?
【解决方案2】:

首先,您应该使代码尽可能简单明了。 而不是计算 i &lt; a.Row * b.Column 你应该做了 2 fors:

for (int i = 0; i < a.Row; i++)
            for (int j = 0; j < b.Column; j++)
            {
                int tempi = i;
                int tempj = j;
                Thread thread = new Thread(() => VectorMult(tempi, tempj, a, b, result));
                thread.Start();
                threads.Add(thread);
            }

然后,在 VectorMult(int tmpi, int tmpj, Matrix a, Matrix b, Matrix result) 函数中,您不计算 j = tempi % b.Column 的东西,而是将其作为参数 tempj。有了 ij 就变成了:

        int i = tmpi;
        int j = tmpj;
        double[] x = a.GetRow(i);
        double[] y = b.GetColumn(j);
        for (int k = 0; k < x.Length; k++)
            result[i, j] += x[k] * y[k];

最后,不要忘记在使用共享资源和线程时,事情可能会变得非常疯狂。确保使用互斥锁。

这里有我的全部代码,

    using System;
    using System.Threading;
    using System.Collections.Generic;

    namespace MatrixMultiplication
    {
    class Matrix
    {
        public int Row { get; set; }
        public int Column { get; set; }
        double[,] arr;
        public static Mutex mutex = new Mutex();

        Matrix() { }
        public Matrix(int row, int column)
        {
            Row = row;
            Column = column;
            arr = new double[row, column];
        }
        public double[] GetColumn(int i)
        {
            double[] res = new double[Row];
            for (int j = 0; j < Row; j++)
                res[j] = arr[j, i];
            return res;
        }
        public double[] GetRow(int i)
        {
            double[] res = new double[Column];
            for (int j = 0; j < Column; j++)
                res[j] = arr[i, j];
            return res;
        }
        public double this[int i, int j]
        {
            get { return arr[i, j]; }
            set { arr[i, j] = value; }
        }
        public Matrix RandomValues()
        {
            Random rnd = new Random();
            for (int i = 0; i < Row; i++)
                for (int j = 0; j < Column; j++)
                    arr[i, j] = rnd.Next(10);
            return this;
        }

        public void Print()
        {
            for (int i = 0; i < Row; i++)
            {
                for (int j = 0; j < Column; j++)
                    Console.Write(arr[i, j] + " ");
                Console.WriteLine();
            }
        }

        public static Matrix operator *(Matrix a, Matrix b)
        {
            Matrix result = new Matrix(a.Row, b.Column);
            List<Thread> threads = new List<Thread>();
            for (int i = 0; i < a.Row; i++)
                for (int j = 0; j < b.Column; j++)
                {
                    int tempi = i;
                    int tempj = j;
                    Thread thread = new Thread(() => VectorMult(tempi, tempj, a, b, result));
                    thread.Start();
                    threads.Add(thread);
                }
            foreach (Thread t in threads)
                t.Join();
            return result;
        }

        public static void VectorMult(int tmpi, int tmpj, Matrix a, Matrix b, Matrix result)
        {
            mutex.WaitOne();
            int i = tmpi;
            int j = tmpj;
            double[] x = a.GetRow(i);
            double[] y = b.GetColumn(j);

            for (int k = 0; k < x.Length; k++)
                result[i, j] += x[k] * y[k];

            mutex.ReleaseMutex();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("n=");
            int n = int.Parse(Console.ReadLine());
            Console.Write("m=");
            int m = int.Parse(Console.ReadLine());
            Console.Write("k=");
            int k = int.Parse(Console.ReadLine());
            Matrix A = new Matrix(n, m).RandomValues();
            Matrix B = new Matrix(m, k).RandomValues();
            A.Print();
            Console.WriteLine(new String('-', 20));
            B.Print();
            Console.WriteLine(new String('-', 20));
            Matrix C = A * B;
            C.Print();
            Console.ReadLine();
        }
    }
}

祝你一切顺利! :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多