2016-04-02 7 views
0

У меня есть задача - написать многопоточное матричное умножение. Каждое векторное произведение должно быть рассчитано в новом потоке. (Если у нас есть матрицы n на m и m на k, мы должны иметь n потоками k). Также я должен показать порядок вычисления элементов матрицы результатов. Я написал код и получил странный результат - порядок расчета почти последовательно. Но я вычисляю каждый элемент в новом потоке, поэтому я должен получить случайный порядок вычисления элементов матрицы результатов. Что не так? Это мой код.Множественное умножение матрицы в C#

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

Пожалуйста, ознакомьтесь с примечаниями к курсовой работе. Код, показанный на рисунке, не демонстрирует использование каких-либо примитивов синхронизации, которые, скорее всего, должны присутствовать, чтобы получить пропускную способность (и определенно необходимо, если на самом деле нужно получить правильный результат). –

ответ

2

Что вы описываете это нормально - см this post от ранее сегодня, которая демонстрирует, как процессы в отдельных потоках, не всегда работают в ожидаемой последовательности. Они могут делать так много или большую часть времени, но затем вы получаете какое-то неожиданное поведение.

Должны ли вычисления выполняться в определенной последовательности или вам просто нужно иметь возможность видеть последовательность, в которой они произошли?

Если вы начинаете новые темы, невозможно контролировать последовательность. (Вы уже это видели.) Вы также не можете захватить порядок, в котором они были выполнены, поскольку завершение расчета и запись результата (консоли или любого другого выхода) не является атомной операцией.

Это может произойти:

  1. расчет заканчивается
  2. Расчет B заканчивает
  3. Расчет B записывается
  4. Расчет А записывается

Многопоточность не является большим, когда операции должны происходить в определенной последовательности.

Вы можете вставить результаты ваших вычислений в ConcurrentQueue по мере их заполнения, и последовательность будет преимущественно правильной.

+0

Мне нужно увидеть порядок, в котором вычислены потоки. И я получаю входной почти равный вход в программу без mutlithreading (я печатаю на экране номер элемента матрицы результатов). Но я думаю, что элементы матрицы результатов должны вычисляться в случайном порядке. – Vladyslav

+0

Чтобы убедиться, что я понимаю - вы говорите, что порядок вычислений может быть случайным или что вы хотите сделать его случайным? –

+0

Я хочу сделать это случайным. Но я думаю, что когда я вычисляю элементы результирующей матрицы в разных потоках, порядок вычисления должен быть случайным по умолчанию. Я ошибаюсь? – Vladyslav

Смежные вопросы