Parallel.ForEach / zwei Schleifen machbar?!?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Parallel.ForEach / zwei Schleifen machbar?!?

    Hallo!
    Ich hab zwei Funktionen! Die eine gibt eine List(Of String) zurück mit allen installierten Schriftarten, die andere Funktion gibt mir ein Bitmap eines Zeichens einer Schriftart zurück!

    Jetzt wollte ich gerne beide Funktionen mit parallel.ForEach laufen lassen.


    Parallel.ForEach(InstalledFontCollection.Families, Sub(ByVal _Font)
    sNames.Add(_Font.Name)

    Das klappt!

    Aber wenn ich jetzt noch ein Parallel.ForEach in die Schleife packe bekomme ich Fehler!
    Wie kann ich beide Schleifen parallel laufen lassen??

    Morrison schrieb:

    bekomme ich Fehler!
    Welchen?
    Poste bitte den kompletten relevanten Code.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hmm, also hab halt eine parallel.foreach in eine andere gepackt und er meinte halt das es keine Überladungsauflösung gibt! :/

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Parallel.ForEach(installedFontCollection.Families, Sub(ByVal _Font)
    2. sNames.Add(_Font.Name)
    3. Parallel.ForEach(_Alphabet_NUM, Sub(ByVal _char)
    4. Form1.getLetterFromFont(_Font.Name, _char, 24, Nothing, True)
    5. End Sub)
    6. End Sub)



    Also ich hab zwei Schleifen die ineinander laufen und die ich beide mit parallel.foreach laufen lassen möchte..erst alle Schriftarten holen..dann von jedem Char jeder Schriftart ein Bitmap erstellen 8|

    ..denke des parallel.foreach ineinander wegen der zwei List(of ..) nicht funktioniert..da weiß das eine foreach nix vom annern!


    Kopmlett:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Imports System.Threading.Tasks
    3. Imports System.Drawing.Text
    4. Public Class Form1
    5. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    6. End Sub
    7. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    8. Dim _allLetters As New _allLetters
    9. ListBox1.DataSource = _allLetters._AllFonts
    10. ListBox1.Invalidate()
    11. End Sub
    12. Public Shared Function getLetterFromFont(ByVal sFontname As String, ByVal c As Char, Optional _iFontSize As Integer = 24, Optional _bitmap As Bitmap = Nothing, Optional _quali As Boolean = False) As Bitmap
    13. Dim bmp As New Bitmap(50, 50)
    14. If _bitmap IsNot Nothing Then
    15. bmp = _bitmap
    16. End If
    17. Dim g As Graphics = Graphics.FromImage(bmp)
    18. Dim font As New Font(sFontname, _iFontSize, FontStyle.Regular, GraphicsUnit.Point)
    19. g.Clear(Color.White)
    20. If _quali = True Then
    21. g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
    22. g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    23. g.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
    24. Else
    25. g.InterpolationMode = Drawing2D.InterpolationMode.Low
    26. g.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed
    27. g.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighSpeed
    28. End If
    29. g.DrawString(c.ToString, font, New SolidBrush(Color.Black), New Point(1, 1))
    30. g.Dispose()
    31. Return bmp
    32. End Function
    33. End Class
    34. Public Class _allLetters
    35. Private Const _Alphabet_NUM As String = "abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ1234567890"
    36. Public Sub New()
    37. Dim sNames As New List(Of String)
    38. Dim installedFontCollection As New InstalledFontCollection()
    39. Parallel.ForEach(installedFontCollection.Families, Sub(ByVal _Font)
    40. sNames.Add(_Font.Name)
    41. 'Parallel.ForEach(_Alphabet_NUM, Sub(ByVal _char)
    42. ' Form1.getLetterFromFont(_Font.Name, _char, 24, Nothing, True)
    43. ' End Sub)
    44. End Sub)
    45. _AllFonts = sNames
    46. End Sub
    47. Private bBitmap As Bitmap
    48. Public Property _Bitmap As Bitmap
    49. Get
    50. Return bBitmap
    51. End Get
    52. Set(value As Bitmap)
    53. bBitmap = value
    54. End Set
    55. End Property
    56. Private lAllFonts As New List(Of String)
    57. Public Property _AllFonts As List(Of String)
    58. Get
    59. Return lAllFonts
    60. End Get
    61. Set(value As List(Of String))
    62. lAllFonts = value
    63. End Set
    64. End Property
    65. 'Private entry As DataRow
    66. 'Public Property _dataRow As DataRow
    67. ' Get
    68. ' Return entry
    69. ' End Get
    70. ' Set(value As DataRow)
    71. ' entry = value
    72. ' End Set
    73. 'End Property
    74. End Class

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Morrison“ ()

    Morrison schrieb:

    Hmm
    Zwei Parallel.ForEach-Schleifen ineinander sind suboptimal.
    Die äußere verteilt die Aufgaben auf alle (zur Verfügung gestellten) Kerne, da kann die innere einfach nur rumpfuschen.
    Zwei ineinander geschachtelte Lambda-Ausdrücke sind einfach ein NoGo, wenn da was nicht funktioniert, bist Du nicht in der Lage, da einen Fehler zu lokalisieren.
    Die Prozedur getLetterFromFont wird ausschließlich in der Klasse _allLetters verwendet, also pack sie da hinein.
    Wenn deren Parametrierung eindeutig ist, überführe die optionalen Parameter in nicht optionale Parameter.
    Also:
    Mach zunächst eine Version, die ohne Parallel funktioniert.
    Wenn sie funktioniert, reden wir über Parallelisierung und Performance.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also ich hatte vorher schon nen laufendes Proggi..mit LockBits usw..
    ..hier erstmal was funzt! Ich hab auf meiner Form eine ListBox, zwei Buttons und eine PictureBox!

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Imports System.Threading.Tasks
    3. Imports System.Drawing.Text
    4. Public Class Form1
    5. Private Const _Alphabet_NUM As String = "abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ1234567890"
    6. Dim sNames As New List(Of String)
    7. Dim lBitmaps As New List(Of Bitmap)
    8. Dim installedFontCollection As New InstalledFontCollection()
    9. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    10. End Sub
    11. Public Shared Function getLetterFromFont(ByVal sFontname As String, ByVal c As Char) As Bitmap
    12. Dim bmp As New Bitmap(50, 50)
    13. Dim g As Graphics = Graphics.FromImage(bmp)
    14. Dim font As New Font(sFontname, 24, FontStyle.Regular, GraphicsUnit.Point)
    15. g.Clear(Color.White)
    16. 'If _quali = True Then
    17. ' g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
    18. ' g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    19. ' g.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
    20. 'Else
    21. ' g.InterpolationMode = Drawing2D.InterpolationMode.Low
    22. ' g.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed
    23. ' g.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighSpeed
    24. 'End If
    25. g.DrawString(c.ToString, font, New SolidBrush(Color.Black), New Point(1, 1))
    26. g.Dispose()
    27. Return bmp
    28. End Function
    29. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles bGetFonts.Click
    30. 'Parallel.ForEach(installedFontCollection.Families, Sub(ByVal _Font)
    31. ' sNames.Add(_Font.Name)
    32. ' End Sub)
    33. For Each _font As FontFamily In installedFontCollection.Families
    34. sNames.Add(_font.Name)
    35. For Each _char As Char In _Alphabet_NUM
    36. lBitmaps.Add(getLetterFromFont(_font.Name, _char))
    37. Next
    38. Next
    39. Debug.WriteLine("Ready!")
    40. ListBox1.DataSource = sNames
    41. ListBox1.Invalidate()
    42. bGetLetters.Enabled = True
    43. End Sub
    44. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles bGetLetters.Click
    45. For Each _bmp As Bitmap In lBitmaps
    46. Application.DoEvents()
    47. PictureBox1.Image = _bmp
    48. PictureBox1.Invalidate()
    49. 'Debug.WriteLine(lBitmaps.IndexOf(_bmp))
    50. Next
    51. End Sub
    52. End Class


    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Morrison“ ()

    @Morrison Try this:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles bGetFonts.Click
    2. Parallel.ForEach(installedFontCollection.Families, AddressOf Me.AddFont)
    3. 'For Each _font As FontFamily In installedFontCollection.Families
    4. ' AddFont(_font)
    5. 'Next
    6. Debug.WriteLine("Ready!")
    7. ListBox1.DataSource = sNames
    8. ListBox1.Invalidate()
    9. bGetLetters.Enabled = True
    10. End Sub
    11. Private Sub AddFont(_font As FontFamily)
    12. sNames.Add(_font.Name)
    13. For Each _char As Char In _Alphabet_NUM
    14. lBitmaps.Add(getLetterFromFont(_font.Name, _char))
    15. Next
    16. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ErfinderDesRades schrieb:

    Gegenprobe
    Bei mir den gefühlten Faktor 5.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ErfinderDesRades , @Morrison
    Ich hab mal gestoppt, totale Ernüchterung:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim sw = Stopwatch.StartNew
    2. If flag Then
    3. Parallel.ForEach(installedFontCollection.Families, AddressOf Me.AddFont)
    4. Else
    5. For Each _font As FontFamily In installedFontCollection.Families
    6. AddFont(_font)
    7. Next
    8. End If
    9. sw.Stop()
    mehrmals aufgerufen, praktisch identisch, 1,2 ... 1,3 s.
    =====
    Dann hab ich die innere Schleife parallelisiert,
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private _fontName As String
    2. Private Sub AddFont(_font As FontFamily)
    3. _fontName = _font.Name
    4. sNames.Add(_fontName)
    5. If flag Then
    6. Parallel.ForEach(_Alphabet_NUM, AddressOf Me.AddBitmap)
    7. Else
    8. For Each _char As Char In _Alphabet_NUM
    9. AddBitmap(_char)
    10. Next
    11. End If
    12. End Sub
    13. Private Sub AddBitmap(_char As Char)
    14. lBitmaps.Add(getLetterFromFont(_fontName, _char))
    15. End Sub
    da sieht es ganz anders aus:
    Normal: 1,2 s, parallel: 1,3 s (bei mehreren Versuchen etwa konstanter Abstand)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private flag As Boolean = True
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles bGetFonts.Click
    3. flag = Not flag
    4. Dim sw = Stopwatch.StartNew
    5. For Each _font As FontFamily In installedFontCollection.Families
    6. AddFont(_font)
    7. Next
    8. sw.Stop()
    9. If flag Then
    10. Label1.Text = "Parallel: " + sw.ElapsedMilliseconds.ToString
    11. Else
    12. Label2.Text = "Normal: " + sw.ElapsedMilliseconds.ToString
    13. End If
    14. Debug.WriteLine("Ready!")
    15. ListBox1.DataSource = sNames
    16. ListBox1.Invalidate()
    17. bGetLetters.Enabled = True
    18. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Morrison schrieb:

    schneller
    Sollte sein.
    Probier es aus und überrasche uns mit dem Ergebnis. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!