Desempenho de matrizes versus listas

Digamos que você precisa ter uma lista / matriz de números inteiros que você precisa repetir com freqüência, e quero dizer com muita frequência. As razões podem variar, mas dizem que está no centro do loop mais interno de um processamento de alto volume.

Em geral, um optaria por usar listas (lista) devido à sua flexibilidade no tamanho. Além disso, as alegações de documentação do msdn Lists usam um array internamente e devem ser executadas com a mesma rapidez (uma rápida olhada com o Reflector confirma isso). Nunca, há alguma sobrecarga envolvida.

Alguém realmente mediu isso? iterar 6M vezes através de uma lista tomar o mesmo tempo que um array faria?

Muito fácil de medir …

Em um pequeno número de código de processamento tight-loop onde eu sei que o comprimento é fixo, eu uso arrays para aquele pouquinho extra de micro-otimização; matrizes podem ser ligeiramente mais rápidas se você usar o indexador / para formulário – mas a IIRC acredita que isso depende do tipo de dados na matriz. Mas, a menos que você precise otimizar o micro, mantenha-o simples e use List etc.

Claro, isso só se aplica se você estiver lendo todos os dados; um dictionary seria mais rápido para pesquisas baseadas em chave.

Aqui estão meus resultados usando “int” (o segundo número é uma sum de verificação para verificar se todos fizeram o mesmo trabalho):

(editado para corrigir bug)

 List/for: 1971ms (589725196) Array/for: 1864ms (589725196) List/foreach: 3054ms (589725196) Array/foreach: 1860ms (589725196) 

com base no equipamento de teste:

 using System; using System.Collections.Generic; using System.Diagnostics; static class Program { static void Main() { List list = new List(6000000); Random rand = new Random(12345); for (int i = 0; i < 6000000; i++) { list.Add(rand.Next(5000)); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.ReadLine(); } } 

Resposta curta:

significado da cor

Array vs lista vs lista vinculada

Resposta mais detalhada você encontrará pelo seguinte link: https://stackoverflow.com/a/29263914/4423545

Eu acho que o desempenho será bem parecido. A sobrecarga envolvida ao usar uma Lista vs uma Matriz é IMHO quando você adiciona itens à lista e quando a lista precisa aumentar o tamanho da matriz que está usando internamente, quando a capacidade da matriz é atingida.

Suponha que você tenha uma Lista com uma Capacidade de 10, então a Lista aumentará sua capacidade quando você quiser adicionar o 11º elemento. Você pode diminuir o impacto no desempenho inicializando a Capacidade da lista com o número de itens que ela conterá.

Mas, para descobrir se a iteração de uma lista é tão rápida quanto a de uma matriz, por que você não a avalia?

 int numberOfElements = 6000000; List theList = new List (numberOfElements); int[] theArray = new int[numberOfElements]; for( int i = 0; i < numberOfElements; i++ ) { theList.Add (i); theArray[i] = i; } Stopwatch chrono = new Stopwatch (); chrono.Start (); int j; for( int i = 0; i < numberOfElements; i++ ) { j = theList[i]; } chrono.Stop (); Console.WriteLine (String.Format("iterating the List took {0} msec", chrono.ElapsedMilliseconds)); chrono.Reset(); chrono.Start(); for( int i = 0; i < numberOfElements; i++ ) { j = theArray[i]; } chrono.Stop (); Console.WriteLine (String.Format("iterating the array took {0} msec", chrono.ElapsedMilliseconds)); Console.ReadLine(); 

No meu sistema; iterar pelo array levou 33msec; a iteração na lista levou 66 ms.

Para ser honesto, não esperava que a variação fosse tanto assim. Então, eu coloquei minha iteração em um loop: agora, eu executo a iteração 1000 vezes. Os resultados são:

iterando a lista levou 67146 ms iterando a matriz levou 40821 ms

Agora, a variação não é tão grande assim, mas ainda assim ...

Portanto, eu iniciei o .NET Reflector, e o getter do indexador da class List, se parece com isto:

 public T get_Item(int index) { if (index >= this._size) { ThrowHelper.ThrowArgumentOutOfRangeException(); } return this._items[index]; } 

Como você pode ver, quando você usa o indexador da Lista, a Lista executa uma verificação se você não está saindo dos limites da matriz interna. Esta verificação adicional vem com um custo.

se você está apenas obtendo um único valor de um dos dois (não em um loop), então ambos fazem a verificação de limites (você está no código gerenciado, lembre-se) é apenas a lista faz isso duas vezes. Veja as notas mais tarde por que isso provavelmente não é grande coisa.

Se você está usando o seu próprio para (int int i = 0; i

  • Array:
    • verificação de limites é removida
  • Listas
    • verificação de limites é executada

Se você estiver usando foreach, a diferença principal é a seguinte:

  • Array:
    • nenhum object é alocado para gerenciar a iteração
    • verificação de limites é removida
  • Listar por meio de uma variável conhecida como List.
    • a variável de gerenciamento de iteração é alocada em pilha
    • verificação de limites é executada
  • Listar por meio de uma variável conhecida como IList.
    • a variável de gerenciamento de iteração é heap alocada
    • A verificação de limites é executada também. Os valores de listas não podem ser alterados durante o foreach, enquanto os da matriz podem ser.

A verificação dos limites geralmente não é grande coisa (especialmente se você estiver em uma cpu com previsão profunda de stream e ramificação – a norma para a maioria desses dias), mas apenas o seu próprio perfil pode dizer se isso é um problema. Se você estiver em partes do seu código em que está evitando alocações de heap (bons exemplos são bibliotecas ou em implementações de código hash), então, assegurar que a variável seja digitada como List not IList evitará essa armadilha. Como sempre perfil se importa.

[ Veja também esta pergunta ]

Eu modifiquei a resposta de Marc para usar números randoms reais e realmente fazer o mesmo trabalho em todos os casos.

Resultados:

          para foreach
 Matriz: 1575 ms 1575 ms (+ 0%)
 Lista: 1630ms 2627ms (+ 61%)
          (+ 3%) (+ 67%)

 (Checksum: -1000038876)

Compilado como Release no VS 2008 SP1. Correndo sem debugging em um Q6600@2.40GHz, .NET 3.5 SP1.

Código:

 class Program { static void Main(string[] args) { List list = new List(6000000); Random rand = new Random(1); for (int i = 0; i < 6000000; i++) { list.Add(rand.Next()); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = arr.Length; for (int i = 0; i < len; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.WriteLine(); Console.ReadLine(); } } 

As medidas são boas, mas você obterá resultados significativamente diferentes dependendo do que estiver fazendo exatamente no seu loop interno. Meça sua própria situação. Se você estiver usando multi-threading, só isso é uma atividade não trivial.

De fato, se você executar alguns cálculos complexos dentro do loop, então o desempenho do indexador de array versus o indexador de lista pode ser tão marginalmente pequeno que, eventualmente, não importa.

Não tente adicionar capacidade aumentando o número de elementos.

atuação

 List For Add: 1ms Array For Add: 2397ms 

  Stopwatch watch; #region --> List For Add < -- List intList = new List(); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 60000; rpt++) { intList.Add(rand.Next()); } watch.Stop(); Console.WriteLine("List For Add: {0}ms", watch.ElapsedMilliseconds); #endregion #region --> Array For Add < -- int[] intArray = new int[0]; watch = Stopwatch.StartNew(); int sira = 0; for (int rpt = 0; rpt < 60000; rpt++) { sira += 1; Array.Resize(ref intArray, intArray.Length + 1); intArray[rpt] = rand.Next(); } watch.Stop(); Console.WriteLine("Array For Add: {0}ms", watch.ElapsedMilliseconds); #endregion 

Aqui está um que usa dictionarys, IEnumerable:

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; static class Program { static void Main() { List list = new List(6000000); for (int i = 0; i < 6000000; i++) { list.Add(i); } Console.WriteLine("Count: {0}", list.Count); int[] arr = list.ToArray(); IEnumerable Ienumerable = list.ToArray(); Dictionary dict = list.ToDictionary(x => x, y => true); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in Ienumerable) { chk += i; } } Console.WriteLine("Ienumerable/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += i; } } Console.WriteLine("Dict/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in Ienumerable) { chk += i; } } watch.Stop(); Console.WriteLine("Ienumerable/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += i; } } watch.Stop(); Console.WriteLine("Dict/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.ReadLine(); } } 

Como List <> usa matrizes internamente, o desempenho básico deve ser o mesmo. Por duas razões, porque a lista pode ser um pouco mais lenta:

  • Para procurar um elemento na lista, é chamado um método de List, que faz a pesquisa no array subjacente. Então você precisa de uma chamada de método adicional lá. Por outro lado, o compilador pode reconhecer isso e otimizar a chamada “desnecessária”.
  • O compilador pode fazer algumas otimizações especiais se conhecer o tamanho da matriz, o que não pode ser feito para uma lista de tamanho desconhecido. Isso pode trazer alguma melhoria no desempenho se você tiver apenas alguns elementos em sua lista.

Para verificar se isso faz alguma diferença para você, provavelmente é melhor ajustar as funções de tempo postadas para uma lista do tamanho que você está planejando usar e ver como estão os resultados para o seu caso especial.

Eu estava preocupado que os Benchmarks postados em outras respostas ainda deixassem espaço para o compilador otimizar, eliminar ou mesclar loops, então eu escrevi um que:

  • Usou inputs imprevisíveis (aleatórias)
  • Executa um calculado com o resultado impresso no console
  • Modifica os dados de input em cada repetição

O resultado é que uma matriz direta tem cerca de 250% melhor desempenho do que um access a uma matriz envolvida em um IList:

  • 1 bilhão de accesss de array: 4000 ms
  • 1 bilhão de accesss de lista: 10000 ms
  • 100 milhões de accesss à matriz: 350 ms
  • 100 milhões de accesss de lista: 1000 ms

Aqui está o código:

 static void Main(string[] args) { const int TestPointCount = 1000000; const int RepetitionCount = 1000; Stopwatch arrayTimer = new Stopwatch(); Stopwatch listTimer = new Stopwatch(); Point2[] points = new Point2[TestPointCount]; var random = new Random(); for (int index = 0; index < TestPointCount; ++index) { points[index].X = random.NextDouble(); points[index].Y = random.NextDouble(); } for (int repetition = 0; repetition <= RepetitionCount; ++repetition) { if (repetition > 0) { // first repetition is for cache warmup arrayTimer.Start(); } doWorkOnArray(points); if (repetition > 0) { // first repetition is for cache warmup arrayTimer.Stop(); } if (repetition > 0) { // first repetition is for cache warmup listTimer.Start(); } doWorkOnList(points); if (repetition > 0) { // first repetition is for cache warmup listTimer.Stop(); } } Console.WriteLine("Ignore this: " + points[0].X + points[0].Y); Console.WriteLine( string.Format( "{0} accesses on array took {1} ms", RepetitionCount * TestPointCount, arrayTimer.ElapsedMilliseconds ) ); Console.WriteLine( string.Format( "{0} accesses on list took {1} ms", RepetitionCount * TestPointCount, listTimer.ElapsedMilliseconds ) ); } private static void doWorkOnArray(Point2[] points) { var random = new Random(); int pointCount = points.Length; Point2 accumulated = Point2.Zero; for (int index = 0; index < pointCount; ++index) { accumulated.X += points[index].X; accumulated.Y += points[index].Y; } accumulated /= pointCount; // make use of the result somewhere so the optimizer can't eliminate the loop // also modify the input collection so the optimizer can merge the repetition loop points[random.Next(0, pointCount)] = accumulated; } private static void doWorkOnList(IList points) { var random = new Random(); int pointCount = points.Count; Point2 accumulated = Point2.Zero; for (int index = 0; index < pointCount; ++index) { accumulated.X += points[index].X; accumulated.Y += points[index].Y; } accumulated /= pointCount; // make use of the result somewhere so the optimizer can't eliminate the loop // also modify the input collection so the optimizer can merge the repetition loop points[random.Next(0, pointCount)] = accumulated; } 

Desde que eu tive uma pergunta semelhante, isso me deu um começo rápido.

Minha pergunta é um pouco mais específica: ‘qual é o método mais rápido para uma implementação de array reflexivo’

O teste feito por Marc Gravell mostra muito, mas não exatamente o tempo de access. Seu timing inclui o loop sobre as listas e listas também. Como eu também criei um terceiro método que queria testar, um ‘Dicionário’, só para comparar, estendi o código de teste da hist.

Firts, eu faço um teste usando uma constante, o que me dá um certo tempo, incluindo o loop. Este é um tempo ‘vazio’, excluindo o access real. Então eu faço um teste com o access à estrutura de assunto, isso me dá e ‘sobrecarga incluída’ cronometragem, looping e access real.

A diferença entre a temporização ‘nua’ e a temporização ‘sobrecarga isolada’ me dá uma indicação do tempo de ‘access à estrutura’.

Mas quão preciso é esse momento? Durante as janelas de teste, haverá algum tempo para fatiar. Eu não tenho nenhuma informação sobre o fatiamento do tempo, mas suponho que ele seja distribuído uniformemente durante o teste e na ordem de dezenas de ms, o que significa que a precisão do tempo deve ser da ordem de +/- 100 mseg. Um pouco de estimativa aproximada? De qualquer forma, uma fonte de um erro sistemático de mearure.

Além disso, os testes foram feitos no modo ‘Debug’ sem otimização. Caso contrário, o compilador pode alterar o código de teste real.

Então, eu recebo dois resultados, um para uma constante, marcado como ‘(c)’, e um para o access marcado ‘(n)’ e a diferença ‘dt’ me diz quanto tempo o access real leva.

E estes são os resultados:

  Dictionary(c)/for: 1205ms (600000000) Dictionary(n)/for: 8046ms (589725196) dt = 6841 List(c)/for: 1186ms (1189725196) List(n)/for: 2475ms (1779450392) dt = 1289 Array(c)/for: 1019ms (600000000) Array(n)/for: 1266ms (589725196) dt = 247 Dictionary[key](c)/foreach: 2738ms (600000000) Dictionary[key](n)/foreach: 10017ms (589725196) dt = 7279 List(c)/foreach: 2480ms (600000000) List(n)/foreach: 2658ms (589725196) dt = 178 Array(c)/foreach: 1300ms (600000000) Array(n)/foreach: 1592ms (589725196) dt = 292 dt +/-.1 sec for foreach Dictionary 6.8 7.3 List 1.3 0.2 Array 0.2 0.3 Same test, different system: dt +/- .1 sec for foreach Dictionary 14.4 12.0 List 1.7 0.1 Array 0.5 0.7 

Com melhores estimativas sobre os erros de tempo (como remover o erro de medição sistemática devido ao fatiamento de tempo?), Mais poderia ser dito sobre os resultados.

Parece que List / foreach tem o access mais rápido, mas a sobrecarga está acabando com ele.

A diferença entre List / for e List / foreach é stange. Talvez algum dinheiro esteja envolvido?

Além disso, para o access a uma matriz, não importa se você usa um loop for ou um loop foreach . Os resultados de temporização e sua precisão tornam os resultados “comparáveis”.

Usando um dictionary é de longe o mais lento, eu só considerei porque no lado esquerdo (o indexador) eu tenho uma lista esparsa de inteiros e não um intervalo como é usado neste testes.

Aqui está o código de teste modificado.

 Dictionary dict = new Dictionary(6000000); List list = new List(6000000); Random rand = new Random(12345); for (int i = 0; i < 6000000; i++) { int n = rand.Next(5000); dict.Add(i, n); list.Add(n); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = dict.Count; for (int i = 0; i < len; i++) { chk += 1; // dict[i]; } } watch.Stop(); long c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Dictionary(c)/for: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = dict.Count; for (int i = 0; i < len; i++) { chk += dict[i]; } } watch.Stop(); long n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Dictionary(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += 1; // list[i]; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(c)/for: {0}ms ({1})", c_dt, chk); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += 1; // arr[i]; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Array(c)/for: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Array(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += 1; // dict[i]; ; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine("Dictionary[key](c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += dict[i]; ; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Dictionary[key](n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += 1; // i; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += 1; // i; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Array(c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Array(n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); 

Em alguns testes breves, descobri que uma combinação dos dois é melhor no que eu chamaria de matemática razoavelmente intensiva:

Tipo: List

Horário: 00: 00: 05.1861300

Tipo: List>

Horário: 00: 00: 05.7941351

Tipo: double[rows * columns]

Horário: 00: 00: 06.0547118

Executando o código:

 int rows = 10000; int columns = 10000; IMatrix Matrix = new IMatrix(rows, columns); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int r = 0; r < Matrix.Rows; r++) for (int c = 0; c < Matrix.Columns; c++) Matrix[r, c] = Math.E; for (int r = 0; r < Matrix.Rows; r++) for (int c = 0; c < Matrix.Columns; c++) Matrix[r, c] *= -Math.Log(Math.E); stopwatch.Stop(); TimeSpan ts = stopwatch.Elapsed; Console.WriteLine(ts.ToString()); 

Eu gostaria que tivéssemos algumas classs de Matriz de Aceleração de Hardware de alto nível como a Equipe .NET fizeram com a Classe System.Numerics.Vectors !

C # poderia ser o melhor ML Language com um pouco mais de trabalho nesta área!