Lsteinme Geschrieben 16. April 2013 Geschrieben 16. April 2013 Hi Leute, ich hab mal wieder ein Problem^^ Und zwar wollt ich im Geschäft eine relativ umfangreiche Exceltabelle auslesen (über 10k Zeilen) Da das sehr lange dauert, im naitiv Ansatz (ein Thread der alle verwendeten Rows durchläuft) hab ich mir gedacht, versuchs doch mal Multithreaded. Ich hab aktuell ne 3 Klassen Struktur aufgebaut: eine Klasse die die Auslesung anfordert, die tut aber noch mehr, das funktioniert aber schon^^ eine Klasse namens ThreadControl die ich eigentlich nur als Zwischenklasse eingezogen hab, vielleicht braucht man sowas ja nochmal und eine Klasse die den Thread darstellt. Jetzt is aber das Problem: ich bekomm eine HResult Message (0x800A03EC) raus wenn das ganze anfängt zu laufen. Jetzt meine Frage, liegts ehr an meinem Code, oder erlaubt Excel kein auslesen mehrer Threads zugleich? Gruß Lucas Zitieren
lilith2k3 Geschrieben 16. April 2013 Geschrieben 16. April 2013 Hilfreich wäre es, wenn wir a) ein genaueres Konzept lesen könnten, statt einfach nur "ich habe da mal ..." und Code wäre auch ganz nett. Zitieren
Lsteinme Geschrieben 16. April 2013 Autor Geschrieben 16. April 2013 hat sich eh schon erledigt, war ein Problem im Code, die Zentrale Frage: "erlaubt eine Exceldatei mehren Thread gleichzeitig das Lesen aus ihr" kann man übrigens auch ohne Code beantworten: Ja es funktioniert Zitieren
Klotzkopp Geschrieben 16. April 2013 Geschrieben 16. April 2013 die Zentrale Frage: "erlaubt eine Exceldatei mehren Thread gleichzeitig das Lesen aus ihr" kann man übrigens auch ohne Code beantworten: Ja es funktioniert Eine Excel-Datei für sich allein kann gar nichts erlauben, da muss schon ein ausführbares Programm dahinter stehen, das eine entsprechende Schnittstelle anbietet. Dass die Schnittstelle, die du da benutzt hast, threadsicher ist, heißt nicht, dass das für jede Schnittstelle gilt. Insoweit wäre es durchaus nützlich gewesen, wenn du wenigstens erwähnt hättest, wie du auf die Daten zugegriffen hast. Zitieren
Lsteinme Geschrieben 16. April 2013 Autor Geschrieben 16. April 2013 ok, Dim myExportSheet As Worksheet = CType(excelApp.Workbooks.Open(importfile).Sheets.Item(1), Worksheet) war der code der mir das Worksheetliefert von dem ich auslesen will, ob das jetzt geklappt hat weiß ich noch net 3 von 4 Threads blieben ganz Blank im result, was nicht sein sollte, aber logische Gründe haben könnte. Von miraus hier mal der relevante Code für die Threadbearbeitung: Aufrufende Klasse die jede menge tut was eigentlich mit dem problem nix zu tun hat: sub FUNKTIONSNAME() Dim myExportSheet As Worksheet = CType(excelApp.Workbooks.Open(importfile).Sheets.Item(1), Worksheet) ... With treadcontrol Dim wieviele As Integer = myExportSheet.UsedRange.Rows.Count Dim rest As Integer = wieviele Mod .anzCores Dim startvalues(.anzCores - 1) As Integer Dim endvalues(.anzCores - 1) As Integer Dim currententry As Integer = 0 For i As Integer = 0 To startvalues.Count - 1 startvalues(i) = currententry + 1 endvalues(i) = CInt(Fix(wieviele / .anzCores)) + currententry currententry = endvalues(i) If ((i + 1).Equals(.anzCores)) Then endvalues(i) = endvalues(i) + (wieviele Mod (.anzCores)) End If treadcontrol.createNewSearchingThread(startvalues(i), endvalues(i), myExportSheet, i) Next End With End Sub 'wenn hier alles gescheit ankommt is der rest egal Public Function resumeRM_Import(e As List(Of UncastedProjektmitarbeiter)) As Boolean Handles ... End Function Klasse ThreadControl: Public Class Threadcontrol Public Event excelloadfinished(list As List(Of UncastedProjektmitarbeiter)) 'this is a current version, if the Working PCs get more cores, increase this number Public anzCores As Integer = 4 Private _oPX_Logic As OPX_Logic Private finished(anzCores - 1) As Boolean Dim ExcelLoadObject(anzCores - 1) As ExcelLoadThread Sub New(oPX_Logic As OPX_Logic) ' TODO: Complete member initialization _oPX_Logic = oPX_Logic End Sub Sub createNewSearchingThread(startvalues As Integer, endvalues As Integer, myExportSheet As Worksheet, i As Integer) ExcelLoadObject(i) = New ExcelLoadThread(startvalues, Me, myExportSheet, i, endvalues) Dim excelloadThread As New Threading.Thread(AddressOf ExcelLoadObject(i).startreading) excelloadThread.Start() End Sub Public Sub threadfinishedHandler(e As Integer) finished(e) = True Dim all As Boolean = True For Each index As Boolean In finished If (index = False) Then all = False Exit For End If Next If (all) Then Dim newList As New List(Of UncastedProjektmitarbeiter) For index As Integer = 0 To anzCores - 1 newList.AddRange(ExcelLoadObject(index).mitarbeiters) Next RaiseEvent excelloadfinished(newList) End If End Sub End Class ThreadKlasse: Imports Microsoft.Office.Interop Imports System.Globalization Public Class ExcelLoadThread Public Event threadfinished(e As Integer) Public mitarbeiters As New List(Of UncastedProjektmitarbeiter) Dim mysheet As Worksheet Dim startrow As Integer Dim endrow As Integer Dim index As Integer Sub New(startrow As Integer, control As Threadcontrol, sheet As Excel.Worksheet, index As Integer, Optional endrow As Integer = 0) Me.startrow = startrow Me.endrow = endrow Me.index = index mysheet = sheet AddHandler threadfinished, AddressOf control.threadfinishedHandler End Sub Sub startreading() For Each r As Excel.Range In mysheet.Range(mysheet.Cells(startrow, 1), mysheet.Cells(endrow, 16)) Dim Rescol As String = CStr(CType(r.Cells(1, 3), Excel.Range).Value) If (String.IsNullOrEmpty(Rescol) OrElse Rescol.Equals("")) Then Exit For End If If (Rescol.Contains("Ressource") Or Rescol.Contains("Gen.Res.")) Then Continue For End If Dim BEcol As String = CStr(CType(r.Cells(1, 5), Excel.Range).Value) If String.IsNullOrEmpty(BEcol) OrElse Not BEcol.Contains("BE") Then Continue For End If Dim datum As Date Date.TryParseExact(CStr(CType(CType(r, Excel.Range).Cells(1, 16), Excel.Range).Value), "dd.MM.yyyy", New CultureInfo("de-DE"), Globalization.DateTimeStyles.None, datum) Dim rollnumber As String = CStr(CType(CType(r, Excel.Range).Cells(1, 6), Excel.Range).Value) mitarbeiters.Add(New UncastedProjektmitarbeiter(Rescol, BEcol, rollnumber, datum)) Next RaiseEvent threadfinished(index) End Sub End Class Hoffe das war nun erhellend ich halts er für verwirrend, weswegen ich den Code nicht gleich gepostet hab^^ Kurz zur Erklärung: das Programm liest eine speziellformatierte Exceldatei ein, parsed die Daten, und speichert sie in der DB (falls sich was geändert hat) im code steht jetzt nur das Excelauslesen Gruß Lucas Zitieren
SilentDemise Geschrieben 16. April 2013 Geschrieben 16. April 2013 wenn du sie nur lesen willst, ist LINQ wesentlich effektiver. Zitieren
Felix91 Geschrieben 17. April 2013 Geschrieben 17. April 2013 Das ist zwar eine nette Behauptung, stimmt aber nicht. LINQ arbeitet intern quasi genau so wie ausgeschriebene Schleifen. In sehr komplexen Abläufen in der Schleife kann man etwas Geschwindigkeit gewinnen, aber in einer einfachen Schleife wird da kein Unterschied sein. Zitieren
SilentDemise Geschrieben 17. April 2013 Geschrieben 17. April 2013 (bearbeitet) LINQ ist extrem effizient beim verarbeiten solch strukturierter daten, da du operationen horizontal und vertikal über die tabelle ausführen kannst. Edith sagt: sample sagt 1 Mio datensätze aus einem excel file: 5,534 sekunden. Ihr Zeuge. Bearbeitet 17. April 2013 von SilentDemise Zitieren
Guybrush Threepwood Geschrieben 17. April 2013 Geschrieben 17. April 2013 LINQ arbeitet intern quasi genau so wie ausgeschriebene Schleifen. Das ist zwar eine nette Behauptung, stimmt aber nicht. Zitieren
Felix91 Geschrieben 18. April 2013 Geschrieben 18. April 2013 (bearbeitet) c# - LINQ performance FAQ - Stack Overflow LINQ vs Loop – A performance test | Circles and Crosses Martin's Blog: C#: LINQ and Foreach performance comparison Quellen für Gegenbehauptungen? PS: Ich möchte LINQ hier nicht schlecht reden - es ist eine der geilsten Techniken im .NET Framework überhaupt. Es geht hier rein um das Thema "Einfache Datenabfrage - Performance Unterschiede" PPS: Wer ganz genau wissen möchte wie LINQ arbeitet: http://www.codeproject.com/Articles/383749/How-does-it-work-in-Csharp-Part-3-Csharp-LINQ-in-d PPPS: SilentDemise, auch mal mit dem herkömmlichen Weg probiert? Am besten du postest hier mal deinen verwendeten Code - oder in einem neuen Thread (das alles gehört hier eigentlich gar nicht hin). Es würde mich sehr überraschen, wenn bei einfachen Datenstrukturen LINQ eine erhöhte Performance ans Tageslicht bringen würde. Bearbeitet 18. April 2013 von Felix91 Zitieren
Guybrush Threepwood Geschrieben 18. April 2013 Geschrieben 18. April 2013 Das ist ja alles schön und gut aber passt leider nicht auf das hier vorliegende Problem. Wenn du eine Linq Abfrage auf eine einfache Collection machst dann wird da natürlich intern auch in einer Schleife oder Iterator drüber gelaufen. Wenn du aber stattdessen eine Linq Abfrage auf eine Datenquelle machst welche zum Beispiel eine Datenbank verbindet, läuft Linq da nicht in einer Schleife über deine Tabellen sondern generiert anhand deiner Linq Abfrage eine entsprechende SQL Abfrage und holt sich darüber die gewünschten Daten. Um jetzt zu wissen was genau bei einer Excel Abfrage passiert muss man wissen welche Möglichkeiten Excel zur Verfügung stellt und wie der DataProvider dafür genau arbeitet. Aber ich wage jetzt mal zu behaupten das da auch nicht einfach in einer Schleife Zelle für Zelle ausgelesen wird. Zitieren
Felix91 Geschrieben 18. April 2013 Geschrieben 18. April 2013 Moment - ich bin davon ausgegangen, dass wir hier die ganze Zeit über linq to object reden. Es ging um eine Datei auslesen - nicht um eine echte Daten Verbindung. Da ich mich nicht im Detail mit interop auskenne, kann ich hierzu jetzt keine qualifizierte Aussage machen. Spontan würde ich behaupten, der DataProvider gibt einfach nur eine collection zurück - womit wir wieder bei linq to object wären. Damit wäre es egal, wie der DataProvider die Daten liest, er hat sie zum Zeitpunkt der Laufzeit im Speicher und die Last liegt in der Anwendung. Das würde ich jetzt dadurch begründen, dass es freie Bibliotheken gibt, die linq to excel ermöglichen (z.B. linqtoexcel - Use LINQ to retrieve data from spreadsheets. - Google Project Hosting ). Hierbei wird dann per OleDB auf die Excel Datei zugegriffen. Dass Linq hier schneller ist, ist ein anderes Thema. Zitieren
lbm1305 Geschrieben 18. April 2013 Geschrieben 18. April 2013 @Felix91 Deine genannten Beispiele sind knapp 3 Jahre alt. Ich habe das Beispiel LINQ vs Loop – A performance test | Circles and Crosses genommen und schnell nachgestellt. Ergebnis: Loop 00:00:00.0600000 linq 00:00:00.1700000 Loop ist hier immer noch etwas schneller, aber das Ergebnis weicht sehr von dem Beispiel ab. Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.