Распараллеливание поэлементного умножения двух матриц в F # - PullRequest
4 голосов
/ 04 июня 2010

Я пытаюсь распараллелить элемент по элементам умножения двух матриц в F #. Я не могу понять это, подумал. Я продолжаю пытаться создавать задачи, но он никогда не хочет компилироваться. Мой нерабочий грязный код выглядит следующим образом:

let myBigElemMultiply (m:matrix) (n:matrix) = 
  let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) =
      for i in 0 .. destination.NumCols
          destination.[row, i] <- source1.[row,i] + source2.[row,i]
      destination
  let result = Matrix.zero(m.NumRows)
  let operations = [ for i in 0 .. m.NumRows -> AddTwoRows i result m n ]
  let parallelTasks = Async.Parallel operations
  Async.RunSynchronously parallelTasks
  result

Ответы [ 3 ]

4 голосов
/ 04 июня 2010

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

let myBigElemMultiply (m:matrix) (n:matrix) = 
  let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) =
      for col=0 to destination.NumCols-1 do
        let mutable sum = 0.0
        for k=0 to m.NumCols-1 do
          sum <- sum + source1.[row,k] * source2.[k,col]
        destination.[row,col] <- sum

  let result = Matrix.zero m.NumRows n.NumCols
  let operations = [ for i=0 to m.NumRows-1 do yield async { AddTwoRows i result m n} ]
  let parallelTasks = Async.Parallel operations
  Async.RunSynchronously parallelTasks |> ignore
  result

Следует отметить, что этот код будет работать очень плохо, потому что m.[i,j] - неэффективный способ доступа к элементам в матрице. Вам лучше использовать 2D-массив:

let myBigElemMultiply2 (m:matrix) (n:matrix) = 
  let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) =
      let destination = destination.InternalDenseValues
      let source1 = source1.InternalDenseValues
      let source2 = source2.InternalDenseValues
      for col=0 to Array2D.length2 destination - 1 do
        let mutable sum = 0.0
        for k=0 to Array2D.length1 source2 - 1 do
          sum <- sum + source1.[row,k] * source2.[k,col]
        destination.[row,col] <- sum

  let result = Matrix.zero m.NumRows n.NumCols
  let operations = [ for i=0 to m.NumRows-1 do yield async { AddTwoRows i result m n} ]
  let parallelTasks = Async.Parallel operations
  Async.RunSynchronously parallelTasks |> ignore
  result

Тестирование:

let r = new Random()
let A = Matrix.init 280 10340 (fun i j -> r.NextDouble() )
let B = A.Transpose

некоторые сроки:

> myBigElemMultiply A B;;
Real: 00:00:22.111, CPU: 00:00:41.777, GC gen0: 0, gen1: 0, gen2: 0
val it : unit = ()
> myBigElemMultiply2 A B;;
Real: 00:00:08.736, CPU: 00:00:15.303, GC gen0: 0, gen1: 0, gen2: 0
val it : unit = ()
> A*B;;
Real: 00:00:13.635, CPU: 00:00:13.166, GC gen0: 0, gen1: 0, gen2: 0
val it : unit = ()
> 

Проверьте здесь с помощью ParallelFor, который должен иметь лучшую производительность, чем асинхронный.

2 голосов
/ 04 июня 2010

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

let myBigElemMultiply (m:matrix) (n:matrix) =  
    let AddTwoRows (row:int) (destination:matrix) (source1:matrix) (source2:matrix) = 
        async {    
            for i in 0 .. destination.NumCols do
                destination.[row, i] <- source1.[row,i] + source2.[row,i] 
        }
    let result = Matrix.zero m.NumRows m.NumCols 
    let operations = [ for i in 0 .. m.NumRows -> AddTwoRows i result m n ] 
    let parallelTasks = Async.Parallel operations 
    Async.RunSynchronously parallelTasks |> ignore
    result 
1 голос
/ 04 июня 2010

Нет смысла. Неуместное поэлементное умножение пары матриц - это немного больше, чем копирование, при котором одно ядро ​​удастся максимально использовать всю пропускную способность памяти вашей машины, а добавление большего количества ядер не улучшит производительность. Так что это почти наверняка пустая трата времени.

...