Nous avons une méthode courte qui analyse le fichier .csv en recherche:
ILookup<string, DgvItems> ParseCsv( string fileName )
{
var file = File.ReadAllLines( fileName );
return file.Skip( 1 ).Select( line => new DgvItems( line ) ).ToLookup( item => item.StocksID );
}
Et la définition de DgvItems:
public class DgvItems
{
public string DealDate { get; }
public string StocksID { get; }
public string StockName { get; }
public string SecBrokerID { get; }
public string SecBrokerName { get; }
public double Price { get; }
public int BuyQty { get; }
public int CellQty { get; }
public DgvItems( string line )
{
var split = line.Split( ',' );
DealDate = split[0];
StocksID = split[1];
StockName = split[2];
SecBrokerID = split[3];
SecBrokerName = split[4];
Price = double.Parse( split[5] );
BuyQty = int.Parse( split[6] );
CellQty = int.Parse( split[7] );
}
}
Et nous avons constaté que si nous ajoutons un supplément ToArray()
avant ToLookup()
comme ceci:
static ILookup<string, DgvItems> ParseCsv( string fileName )
{
var file = File.ReadAllLines( fileName );
return file.Skip( 1 ).Select( line => new DgvItems( line ) ).ToArray().ToLookup( item => item.StocksID );
}
Ce dernier est nettement plus rapide. Plus précisément, lorsque vous utilisez un fichier de test avec 1,4 million de lignes, le premier prend environ 4,3 secondes et le dernier prend environ 3 secondes.
Je pense que cela ToArray()
devrait prendre plus de temps, donc ce dernier devrait être légèrement plus lent. Pourquoi est-ce réellement plus rapide?
Informations supplémentaires:
Nous avons trouvé ce problème car il existe une autre méthode qui analyse le même fichier .csv dans un format différent et cela prend environ 3 secondes, nous pensons donc que celui-ci devrait être capable de faire la même chose en 3 secondes.
Le type de données d'origine est
Dictionary<string, List<DgvItems>>
et le code d'origine n'a pas utilisé linq et le résultat est similaire.
Classe de test BenchmarkDotNet:
public class TestClass
{
private readonly string[] Lines;
public TestClass()
{
Lines = File.ReadAllLines( @"D:\20110315_Random.csv" );
}
[Benchmark]
public ILookup<string, DgvItems> First()
{
return Lines.Skip( 1 ).Select( line => new DgvItems( line ) ).ToArray().ToLookup( item => item.StocksID );
}
[Benchmark]
public ILookup<string, DgvItems> Second()
{
return Lines.Skip( 1 ).Select( line => new DgvItems( line ) ).ToLookup( item => item.StocksID );
}
}
Résultat:
| Method | Mean | Error | StdDev |
|------- |--------:|---------:|---------:|
| First | 2.530 s | 0.0190 s | 0.0178 s |
| Second | 3.620 s | 0.0217 s | 0.0203 s |
J'ai fait une autre base de test sur le code original. Semble que le problème n'est pas sur Linq.
public class TestClass
{
private readonly string[] Lines;
public TestClass()
{
Lines = File.ReadAllLines( @"D:\20110315_Random.csv" );
}
[Benchmark]
public Dictionary<string, List<DgvItems>> First()
{
List<DgvItems> itemList = new List<DgvItems>();
for ( int i = 1; i < Lines.Length; i++ )
{
itemList.Add( new DgvItems( Lines[i] ) );
}
Dictionary<string, List<DgvItems>> dictionary = new Dictionary<string, List<DgvItems>>();
foreach( var item in itemList )
{
if( dictionary.TryGetValue( item.StocksID, out var list ) )
{
list.Add( item );
}
else
{
dictionary.Add( item.StocksID, new List<DgvItems>() { item } );
}
}
return dictionary;
}
[Benchmark]
public Dictionary<string, List<DgvItems>> Second()
{
Dictionary<string, List<DgvItems>> dictionary = new Dictionary<string, List<DgvItems>>();
for ( int i = 1; i < Lines.Length; i++ )
{
var item = new DgvItems( Lines[i] );
if ( dictionary.TryGetValue( item.StocksID, out var list ) )
{
list.Add( item );
}
else
{
dictionary.Add( item.StocksID, new List<DgvItems>() { item } );
}
}
return dictionary;
}
}
Résultat:
| Method | Mean | Error | StdDev |
|------- |--------:|---------:|---------:|
| First | 2.470 s | 0.0218 s | 0.0182 s |
| Second | 3.481 s | 0.0260 s | 0.0231 s |
.ToArray()
, l'appel à .Select( line => new DgvItems( line ) )
renvoie un IEnumerable avant l'appel à ToLookup( item => item.StocksID )
. Et rechercher un élément particulier est pire en utilisant IEnumerable que Array. Probablement plus rapide pour convertir en tableau et effectuer une recherche que d'utiliser un ienumerable.
var file = File.ReadLines( fileName );
- ReadLines
au lieu de ReadAllLines
et votre code sera probablement plus rapide
BenchmarkDotnet
pour la mesure réelle de la perf. Essayez également d'isoler le code réel que vous souhaitez mesurer et n'incluez pas d'E / S dans le test.