Parallelisieren von GDI+ Bild Vergrößern .net
Ich habe versucht zu parallelisieren Sie die Größe der JPEG-Dateien verwenden .Net. Alle meine versuche sind gescheitert, weil die Grafik.DrawImage-func scheint zu sperren, wenn Sie aktiv sind. Versuchen Sie die folgenden Schnitt:
Sub Main()
Dim files As String() = IO.Directory.GetFiles("D:\TEMP")
Dim imgs(25) As Image
For i As Integer = 0 To 25
imgs(i) = Image.FromFile(files(i))
Next
Console.WriteLine("Ready to proceed ")
Console.ReadLine()
pRuns = 1
For i As Integer = 0 To 25
Threading.Interlocked.Increment(pRuns)
Threading.ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf LongTerm), imgs(i))
Next
Threading.Interlocked.Decrement(pRuns)
pSema.WaitOne()
Console.WriteLine("Fin")
Console.ReadLine()
End Sub
Sub LongTerm(ByVal state As Object)
Dim newImageHeight As Integer
Dim oldImage As Image = CType(state, Image)
Dim newImage As Image
Dim graph As Graphics
Dim rect As Rectangle
Dim stream As New IO.MemoryStream
Try
newImageHeight = Convert.ToInt32(850 * oldImage.Height / oldImage.Width)
newImage = New Bitmap(850, newImageHeight, oldImage.PixelFormat)
graph = Graphics.FromImage(newImage)
rect = New Rectangle(0, 0, 850, newImageHeight)
With graph
.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
End With
'Save image to memory stream
graph.DrawImage(oldImage, rect)
newImage.Save(stream, Imaging.ImageFormat.Jpeg)
Catch ex As Exception
Finally
If graph IsNot Nothing Then
graph.Dispose()
End If
If newImage IsNot Nothing Then
newImage.Dispose()
End If
oldImage.Dispose()
stream.Dispose()
Console.WriteLine("JobDone {0} {1}", pRuns, Threading.Thread.CurrentThread.ManagedThreadId)
Threading.Interlocked.Decrement(pRuns)
If pRuns = 0 Then
pSema.Set()
End If
End Try
End Sub
Alle threads warten auf der graph.DrawImage(). Gibt es einen Weg, um die Geschwindigkeit code Leistung mit anderen Funktionen? Ist es unmöglich, die Verwendung von Grafiken.Zeichnen mit mehreren threads? In der realen Anwendung mehrere Bilder sollten verkleinert werden gleichzeitig (auf einem quad-core pc), nicht immer die gleichen. Der gepostete code ist nur für Testzwecke...
Vielen Dank im Voraus
Edit: Aktualisiert den code nach Kommentaren
- Wenn Sie fügen Sie die Deklarationen für pSema und pRuns, wird es einfacher sein, Antworten auf cut-and-paste und testen Sie das proggy.
- Ich habe festgestellt, dass ein großer Teil der Zeit wird damit verbracht, in der IO, nicht in der DrawImage-Aufruf. Wenn Sie das Bild Konstruktor einen stream, vermeiden Sie einige locking-Probleme, die in den decoder. (und es ist etwas schneller). Ich lief einige benchmarks, die beim Bau der imageresizing.net Bibliothek.
- Auch, WIC auf WS2008 R2 und Win7 ist eine gute alternative, und imageresizing.net unterstützt, dass die code-Pfad als eine Reihe von Plug-ins. WPF ist immer noch eine schlechte Idee, auf dem server, zu viele ungepatchte Speicher-Lecks.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Prozesse Nutzen.
GDI+ Blöcke pro Prozess eine Menge von Möglichkeiten. Yep, ein Schmerz, aber es gibt keine Möglichkeit um ihn herum. Zum Glück mit Aufgaben wie diese (und eine, die Prozesse, Dateien auf dem Dateisystem), es ist zu einfach, nur teilen Sie die Arbeitslast zwischen mehreren Prozessen. Glücklicherweise sieht es aus wie GDI+ ist mit sperren, die nicht mutex, so ist es die gleichzeitige!
Wir haben einige Grafik-Programme, wo ich Arbeit zu tun Bildverarbeitung. Ein Programmierer beginnt 6-7 Kopien auf einmal eine Umwandlung Programm, in der Produktion. So ist es nicht unordentlich, Vertrauen Sie mir. Hack? Du bist nicht dafür bezahlt werden, hübsch Aussehen. Den job zu erledigen!
Billig Beispiel (Hinweis: dies funktioniert NICHT in der ide, erstellen Sie und führen Sie die EXE-Datei):
Dispose
ing der Prozesse, wenn Sie mit Ihnen gemacht?Parallel.ForEach
fordertGraphics.DrawImage
; jetzt mitMedia.DrawingContext.DrawImage
aus WPF-ich bekomme voll parallelisiert Leistung. Ich war nicht Rendern alles auf dem Bildschirm—einfach zuschneiden, drehen und speichern auf der Festplatte. Vielleicht ist das Problem speziell fürGraphics.FromImage(Bitmap)
?Ich bin nicht sicher, warum die Ausführung von
Graphics.DrawImage
scheint zu serialisieren für Sie, aber ich habe tatsächlich festgestellt, dass eine race condition mit Ihrer Allgemeinen Muster von Warteschlangen-Arbeitsaufgaben. Das Rennen wird zwischen denWaitOne
und dieSet
. Es ist möglich, für das erste work-item anSet
vor allen anderen schon in der Warteschlange noch. Das wird zuWaitOne
sofort wieder zurück, bevor Sie alle Arbeitsaufgaben abgeschlossen haben.Die Lösung ist zur Behandlung der Haupt-thread, als ob es ein work-item. Inkrement
pRuns
einmal vor, queueing ' beginnt und dann Dekrementieren und signal warten, Griff nach der queueing-vollständig ist genauso, als würden Sie in einem normalen Arbeitsaufgabe. Trotzdem ist der bessere Ansatz ist die Verwendung derCountdownEvent
Klasse, wenn das Ihnen zur Verfügung steht, wie es vereinfacht den code. Wie der Zufall es will Ich habe vor kurzem gepostet das Muster in einer anderen Frage.pRuns
vor der Schleife, und dann verringern Sie es nach dem loop...vor dem AufrufWaitOne
. AlleIncrement
undDecrement
Anrufe Gleichgewicht. Jemand wird schließlich Dekrementieren auf 0. Es könnte ein work-item oder es könnte der Haupt-thread. Sie haben tatsächlich das meiste stimmt schon.Wenn Sie nichts dagegen haben eine WPF-Ansatz, hier etwas zu versuchen. Im folgenden ist ein einfaches skalieren Methode akzeptiert Bild streams und erzeugt ein byte[] mit der resultierenden JPEG-Daten. Da Sie nicht wollen, um tatsächlich ziehen die Bilder mit GDI+, ich dachte, dies sei für Sie geeignet, obwohl Sie WPF-basiert. (Die einzige Voraussetzung ist die Referenz WindowsBase und PresentationCore in Ihrem Projekt.)
Vorteile sind die schnellere Codierung (von 200-300% auf meinem Rechner) und bessere parallele speedup, obwohl ich auch einige unerwünschte Serialisierung des WPF-rendering-Pfad. Lassen Sie mich wissen, wie das funktioniert für Sie. Ich bin sicher, es könnte noch weiter optimiert werden, wenn nötig.
Code:
Verwenden Sie ein image-processing-Bibliothek andere als GDI+.
Verwenden wir ImageMagick auf einem ziemlich high-volume web site Sie skalieren hochgeladene Bilder (die hochgeladenen Bilder sind in der Regel 10-40 MPixel aber in der Lage sein, mit Ihnen zu arbeiten an der website (in Flash-Module), können wir die Größe ändern, Sie haben die kleinste Größe von 1500 Pixel). Die Verarbeitung ist sehr schnell und liefert hervorragende Ergebnisse.
Wir derzeit den start einer neuen ImageMagick-Prozess die Verwendung der Kommandozeilen-Schnittstelle. Dies gibt einige overhead beim starten von neuen Prozessen, aber da die Bilder sind so groß, dass es in der Regel eine ziemlich kleine Zeitscheibe der insgesamt größenänderungsvorgang. Es ist auch möglich, verwenden Sie ImageMagick in-Prozess aber habe noch nicht versucht, doch da es 1. wir brauchen nicht die zusätzliche Leistung, die es gibt und 2. es fühlt sich gut an Drittanbieter-software, die in anderen Prozessen.
Bei der Verwendung von ImageMagick, erhalten Sie auch eine Reihe von anderen Möglichkeiten, wie eine bessere Filterung und viele andere Funktionen.