Est-ce que quelqu'un sait d'une méthode plus rapide à faire String.Split ()?
Je suis à la lecture de chaque ligne d'un fichier CSV et le besoin d'obtenir des valeurs individuelles dans chaque colonne. Donc maintenant je suis juste en utilisant:
values = line.Split(delimiter);
où line
est la chaîne qui détient les valeurs qui sont séparés par le séparateur.
De mesurer les performances de mon ReadNextRow
méthode, j'ai remarqué qu'il passe de 66% sur String.Split
donc je me demandais si quelqu'un connaît une méthode plus rapide pour ce faire.
Merci!
source d'informationauteur
Vous devez vous connecter pour publier un commentaire.
Il convient de rappeler que
split()
est discutable approche pour l'analyse de fichiers CSV dans le cas où vous rencontrez des virgules dans le fichier, par exemple:L'autre chose que je vais souligner sans savoir comment vous le profilé est d'être prudent sur le profilage ce genre de bas niveau de détail. La granularité de la Windows/PC minuterie peut entrer en jeu et vous pouvez avoir une grande-dessus de la tête en boucle donc utiliser une sorte de contrôle de la valeur.
Cela étant dit,
split()
est construit pour gérer les expressions régulières, qui sont évidemment plus complexe que ce que vous avez besoin (et le mauvais outil pour traiter les virgules échappées de toute façon). Aussi,split()
crée beaucoup d'objets temporaires.Donc, si vous voulez accélérer (et j'ai du mal à croire que l'exécution de cette partie est vraiment un problème), alors vous voulez le faire à la main et que vous souhaitez réutiliser votre tampon objets de sorte que vous n'êtes pas en permanence la création d'objets et de donner le garbage collector de travail à faire dans le nettoyage.
De l'algorithme est relativement simple:
Oh, et pour vous donner une idée du coût de la regex, il a été question (Java, C#, mais le principe est le même) où l'on a voulu remplacer tous les n-ième caractère d'une chaîne. J'ai suggéré à l'aide de
replaceAll()
sur la Chaîne. Jon Skeet codées manuellement la boucle. Par curiosité, j'ai comparé les deux versions et c'était un ordre de grandeur mieux.Donc, si vous voulez vraiment de la performance, il est temps de main d'analyser.
Ou, mieux encore, utiliser de quelqu'un d'autre solution optimisée comme ce rapide CSV reader.
Par la voie, tandis que c'est par rapport à Java ce qui concerne la performance des expressions régulières en général (ce qui est universel) et
replaceAll()
vs un codés à la main boucle: Mettre char en java string pour chaque N caractères.La BCL mise en œuvre de la chaîne.Split est en fait assez rapide, j'ai fait quelques tests ici pour essayer de sortir de préformation et il n'est pas facile.
Mais il y a une chose que vous pouvez faire c'est de mettre en œuvre la présente comme un générateur:
La méthode ci-dessus n'est pas nécessairement plus rapide que la chaîne.Split pour les petites chaînes de caractères, mais il renvoie des résultats qu'il les trouve, c'est le pouvoir de l'évaluation différée. Si vous avez de longues lignes ou besoin pour économiser de la mémoire, c'est le chemin à parcourir.
La méthode ci-dessus est limitée par la performance des IndexOf et sous-Chaîne qui fait trop de bien de l'indice de contrôle de la portée et à être plus rapide que vous avez besoin pour optimiser la ces et de mettre en œuvre votre propre helper. Vous pouvez battre la chaîne.Split performances, mais il va prendre cleaver int-piratage. Vous pouvez lire mon post à ce sujet ici.
Selon l'utilisation, vous pouvez accélérer le processus en utilisant le Modèle.diviser au lieu de String.split. Si vous avez ce code dans une boucle (qui, je suppose que vous n'avez probablement car il sonne comme vous êtes l'analyse des lignes à partir d'un fichier) de la Chaîne.split(String regex) Motif d'appel.compiler sur votre regex chaîne à chaque fois que l'instruction de la boucle s'exécute. Afin d'optimiser ce, Modèle.compiler le modèle une fois à l'extérieur de la boucle, puis le profil d'utilisation.split, en passant la ligne que vous voulez diviser, à l'intérieur de la boucle.
Espère que cette aide
J'ai trouvé cette application, qui est 30% plus rapide à partir de Dejan Pelzel blog. Je qoute à partir de là:
La Solution
Comment Utiliser
Cette approche présente des avantages et des inconvénients.
Vous pourriez penser qu'il y a des optimisations, mais la réalité sera que vous aurez à payer pour eux d'ailleurs.
Vous pourriez, par exemple, faire la split "vous-même" et de marcher à travers tous les personnages et les processus de chaque colonne que vous rencontrez, mais vous pourriez être la copie de toutes les pièces de la chaîne dans le long terme de toute façon.
L'une des améliorations que nous pourrions faire en C ou en C++, par exemple, est de remplacer tous les délimiteurs avec les caractères '\0' et de garder des pointeurs vers le début de la colonne. Ensuite, nous n'aurions pas à copier toutes les données de la chaîne juste pour faire une partie. Mais cela, vous ne pouvez pas le faire en C#, ni voulez-vous.
Si il y a une grande différence entre le nombre de colonnes dans la source, et le nombre de colonnes que vous avez besoin, la marche de la chaîne manuellement peut donner un certain avantage. Mais cette prestation vous coûtera le temps de le développer et de le maintenir.
J'ai été dit que 90% du temps CPU est passé de 10% du code. Il existe des variantes à cette "vérité". À mon avis, les dépenses de 66% de votre temps à Split n'est pas si mauvais si le traitement de la CSV est la chose que votre application a besoin de faire.
Dave
Certains analyse très approfondie sur la Chaîne.Fente() vs Regex et d'autres méthodes.
Nous parlons ms économies sur de très grandes chaînes.
Le principal problème(?) avec de la Ficelle.Split est que c'est général, en ce qu'il répond à de nombreux besoins.
Si vous en savez plus au sujet de vos données de Split, il peut apporter une amélioration à faire votre propre.
Par exemple, si:
Si tout ceci est vrai, vous pourriez voir une amélioration en écrivant votre propre en plus de la version spécifique de la Chaîne.Split.
Cela dit, la première question à vous poser est de savoir si c'est vraiment un problème. Est le temps pris à lire et importer le fichier tant que vous avez réellement l'impression que c'est une bonne utilisation de votre temps? Si non, puis je le laisser seul.
La deuxième question est de savoir pourquoi Chaîne.Split est à l'aide de beaucoup de temps par rapport au reste de votre code. Si la réponse est que le code est fait très peu avec les données, alors je ne serais probablement pas la peine.
Toutefois, si, par exemple, vous êtes à la farce les données dans une base de données, puis de 66% du temps de votre code passé en Chaîne.Split constitue un gros gros problème.
CSV analyse est en fait extrêmement complexe pour obtenir le droit, j'ai utilisé les classes en fonction de l'habillage du Texte ODBC pilote la seule fois où j'ai eu à le faire.
ODBC solution recommandée ci-dessus ressemble à première vue à être essentiellement la même approche.
Je recommande absolument vous faites quelques recherches sur CSV analyse avant d'aller trop loin dans une voie qui presque-mais-pas-assez œuvres (trop commun). Excel chose de seulement double-citant les chaînes qui besoin il est l'un des plus délicats à traiter dans mon expérience.
Comme d'autres l'ont dit,
String.Split()
ne fonctionne pas toujours bien avec les fichiers CSV. Envisager un fichier qui ressemble à ça:(par exemple, l'utilisation incohérente de speechmarks, les cordes, y compris les virgules et les speechmarks, etc)
Ce CSV lecture cadre traiter avec tout ce qui est, et est également très efficace:
LumenWorks.Cadre.IO.Csv par Sébastien Lorien
C'est ma solution:
Voici une version avec des performances:
Voici quelques résultats relativement petits, chaînes de caractères, mais avec différentes tailles, jusqu'à des blocs de 8 ko. (les temps sont dans les tiques)
FastSplit a pris 8 alors que split a pris 10
FastSplit a pris 214 alors que split a pris 216
FastSplit a pris 10 alors que split a pris 12
FastSplit a pris 8 alors que split a pris 9
FastSplit a pris 8 alors que split a pris 10
FastSplit a pris 10 alors que split a pris 12
FastSplit a pris 7 alors que split a pris 9
FastSplit a fallu 6 alors que split a pris 8
FastSplit a pris 5, tandis que les split a pris 7
FastSplit a pris 10 alors que split a pris 13
FastSplit a 9 alors que split a pris 232
FastSplit a pris 7 alors que split a pris 8
FastSplit a pris 8 alors que split a pris 9
FastSplit a pris 8 alors que split a pris 10
FastSplit a pris 215 alors que split a pris 217
FastSplit a pris 10 alors que split a pris 231
FastSplit a pris 8 alors que split a pris 10
FastSplit a pris 8 alors que split a pris 10
FastSplit a pris 7 alors que split a pris 9
FastSplit a pris 8 alors que split a pris 10
FastSplit a pris 10 alors que split a pris 1405
FastSplit a 9 alors que split a pris 11
FastSplit a pris 8 alors que split a pris 10
Vous pouvez supposer que la Chaîne.Split sera presque optimale; c'est à dire qu'il pourrait être très difficile de l'améliorer. De loin la plus simple solution consiste à vérifier si vous avez besoin de partager la chaîne. Il est très probable que vous serez à l'aide de la personne directement des chaînes. Si vous définissez un StringShim classe (référence à la Chaîne, commencer & fin de l'index), vous serez en mesure de découper une Chaîne en un jeu de cales à la place. Ces aurez une petite, de taille fixe, et ne causera pas de chaîne de copies de données.
String.split
est plutôt lent, si vous voulez des méthodes plus rapides, ici vous allez. 🙂Cependant CSV est beaucoup mieux analysé par une règle de base de l'analyseur.
Ce gars-là, a fait une règle de tokenizer pour java. (nécessite quelques copier et coller malheureusement)
http://www.csdgn.org/code/rule-tokenizer