简体   繁体   English

C#中的多线程矩阵乘法

[英]Multithreading matrix multiplication in C#

I have a task - write multithreading matrix multiplication. 我有一个任务-写多线程矩阵乘法。 Each vector product must be calculated in new thread.(If we have matrices n by m and m by k we must have n by k threads). 每个向量乘积必须在新线程中计算(如果矩阵n乘m,m乘k,则必须n乘k线程)。 Also I must show order of calculation for elements of result matrix. 我还必须显示结果矩阵元素的计算顺序。 I wrote code and got strange result - order of calculation is almost sequentially. 我写了代码,结果很奇怪-计算顺序几乎是顺序的。 But I calculate each element in new thread, so I must get random order of calculation for elements of the result matrix. 但是我要计算新线程中的每个元素,因此必须对结果矩阵的元素进行随机的计算。 What is wrong? 怎么了? This is my code. 这是我的代码。

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();
    }
  }
}

What you're describing is normal - see this post from earlier today which demonstrates how processes in separate threads don't always operate in the expected sequence. 您所描述的是正常的-请参阅今天早些时候的这篇帖子该帖子演示了独立线程中的进程如何不总是按预期的顺序运行。 They might do so much or most of the time, but then you get some unexpected behavior. 他们可能会在大部分时间或大部分时间内这样做,但是随后您会得到一些意外的行为。

Do the calculations need to occur in a specific sequence, or do you just need to be able to see the sequence in which they occurred? 计算是否需要按照特定的顺序进行,还是只需要能够看到计算的顺序?

If you're starting new threads then it's impossible to control the sequence. 如果要启动新线程,则无法控制顺序。 (You've already seen that.) You also can't capture the order in which they were completed, because completion of a calculation and recording the result (the console or any other output) isn't an atomic operation. (您已经看到了。)您也无法捕获它们的完成顺序,因为完成计算并记录结果(控制台或任何其他输出)不是原子操作。

This could happen: 这可能发生:

  1. Calculation A finishes 计算A完成
  2. Calculation B finishes 计算B完成
  3. Calculation B is recorded 记录了计算B
  4. Calculation A is recorded 记录了计算A

Multithreading isn't great when operations have to occur in a specific sequence. 当操作必须按特定顺序进行时,多线程并不是很好。

You can insert the results of your calculation into a ConcurrentQueue as they are completed, and the sequence will be mostly correct. 您可以在完成计算后将计算结果插入ConcurrentQueue中,并且顺序基本上是正确的。

Firstly, you should keep your code as simple and explicit as possible. 首先,您应该使代码尽可能简单明了。 Instead of calculating i < a.Row * b.Column you should have made 2 for s: 而不是计算i < a.Row * b.Column您应该使s 2:

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);
            }

And then, in the VectorMult(int tmpi, int tmpj, Matrix a, Matrix b, Matrix result) function, instead of calculating that j = tempi % b.Column stuff, you give as parameter tempj . 然后,在VectorMult(int tmpi, int tmpj, Matrix a, Matrix b, Matrix result)函数中,代替计算j = tempi % b.Column东西,而将其作为参数tempj Having i and j it becomes: 有了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];

Finally, don't forget that when working with shared resources and threads, things can go pretty crazy. 最后,不要忘记,在使用共享资源和线程时,事情可能会变得很疯狂。 Make sure you use Mutexes. 确保使用互斥对象。

Here you have my whole code, 这是我的全部代码,

    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();
        }
    }
}

Wish you all the best! 祝你一切顺利! :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM