Ich habe eine Anwendung entwickelt, um E-Mail-Mailer für eine Website über Amazon SES zu senden. Es ist in C # codiert.
Jede E-Mail dauert 0,3 Sekunden, um sie über die Amazon SES-API zu senden. Das heißt, mit einer Single-Thread-Anwendung kann ich nur 3 E-Mails pro Sekunde senden.
Ich habe eine Producer / Consumer, Multithread-Anwendung mit einem Producer implementiert, um die E-Mails für jeden Kunden anzupassen, und 25 Konsumenten, die aus der Warteschlange ziehen und die E-Mails senden.
Meine Multithread-Anwendung sendet 12 E-Mails pro Sekunde (eine vierfache Geschwindigkeitssteigerung). Ich hätte von einer 25-Thread-Anwendung eine höhere Geschwindigkeit erwartet.
Meine Frage ist: Wie viel kann ich wirklich beschleunigen das Senden eines Mailers auf einem Single-Prozessor-Maschine ? Erscheint mein Gewinn vernünftig, oder ist mein Geschwindigkeitsproblem wahrscheinlicher aufgrund der Codierung als aufgrund der Unfähigkeit des Computers, die E-Mails schnell zu verarbeiten?
Vielen Dank im Voraus!
UPDATE: Für den Fall, dass andere das gleiche Problem haben ... Die Verbindung zu AWS, um die E-Mail zu senden, nimmt viel Zeit in Anspruch. Der folgende Thread in AWS Developer-Foren gibt einige Einblicke (Sie müssen möglicherweise einen Bildlauf nach unten durchführen, um zu den nützlicheren Posts zu gelangen).
Meine Frage ist: Wie viel kann ich den Versand eines Mailers wirklich beschleunigen? auf einer Single-Prozessor-Maschine? Sind meine Gewinne vernünftig oder meine? Geschwindigkeitsproblem eher aufgrund der Codierung als der des Computers Unfähigkeit, die E-Mails schneller zu verarbeiten?
Allgemein gesprochen ist eine 4x-Beschleunigung für eine 25-fache Erhöhung der Thread-Anzahl nicht unverschämt, aber auch nicht großartig.
Eine einzelne CPU wird nur dann ein Engpass, wenn Ihre CPU-Auslastung hoch ist. Sie können feststellen, ob dies ein Problem für Sie darstellt, indem Sie sich die Gesamt-CPU-Auslastung bei laufender App ansehen. Theoretisch sollte das Senden von Massen-E-Mails eine E / A-beschränkte Operation sein. Wenn dies für Sie nicht der Fall ist, kann Ihr Code Probleme haben.
Obwohl ich Amazon SES noch nicht verwendet habe, weiß ich, dass andere Amazon-Produkte definitiv verschiedene Formen der Bandbreiten- / Anfragedrosselung verwenden. Es ist möglich (wahrscheinlich), dass Ihr Durchsatz mehr von Amazon als von Ihrer App begrenzt wird.
Ich habe vor einiger Zeit eine leistungsstarke Massenmail-App geschrieben, und was ich getan habe, war:
SmtpClient
verwendet (die eine Methode SendAsync
hat), um die Mail tatsächlich zu senden. Dieser Ansatz ermöglicht es mir auch, Fehler beim Senden der E-Mail zu sehen und aufzuzeichnen, was wiederum den Benutzern ein besseres Feedback gibt. Die Alternative besteht darin, sich auf das Empfangen und Parsen von Fehler-E-Mail vom Gateway-Server zu verlassen, was zumindest fehleranfällig ist.
Ich habe über meine Lösung gebloggt. Grundsätzlich verwenden Sie eine Parallel.ForEach
Schleife mit einem MaxDegreeOfParallelism
, vergessen Sie nicht, die maxconnection
Anzahl in app.config
zu erhöhen.
Unten ist das app.config
Beispiel:
Und hier ist das Parallel.ForEach
loop sample:
Mein Blog erklärt es ausführlicher: Ссылка
In einer Multithread-Anwendung, die auf einem Multi-Core- (oder Multiprozessor-) System ausgeführt wird, ist die goldene Regel, dass Sie im Allgemeinen keine bessere Beschleunigung erreichen als N mal die sequentielle Ausführungszeit, wobei N die Anzahl der Kerne ist. Wenn also eine Aktivität 12 Sekunden dauert und Sie parallel auf 4 Kernen laufen, können Sie insgesamt nicht mehr als 3 Sekunden machen.
Umgekehrt, wenn Sie zuvor eine Aktivität in einer einzigen Zeiteinheit ausführen konnten, können Sie mit 4 Kernen nicht mehr als 4 Aktivitäten in derselben Zeiteinheit ausführen.
Darüber hinaus wird diese obere Grenze nicht immer aufgrund mehrerer Faktoren erreicht, die die Leistung von parallelen Programmen generell beeinflussen: Festplatten-E / A-Engpässe, Speichersättigung, Sperrkonflikte, etc.
Producer Consumer mit nur einer Warteschlange skaliert nicht gut. Die Warteschlange wird zum Engpass, wenn Sie weitere Konsumenten oder Produzenten hinzufügen.
Wenn Sie eine Multiprozessorarchitektur haben, können Sie mehrere Prozesse zum Senden von E-Mails verwenden. Sie können weiterhin Ihre Multithread-Version für Producer Consumer verwenden, aber jetzt wird es ein einziger Prozess sein; das wird die Dinge etwas beschleunigen (wie Tudor erklärt hat), aber das Problem bleibt bestehen.
Sie haben jedoch möglicherweise für das gesamte System nur einen Netzwerkmanager oder eine ähnliche Entität, die die Nachrichten (z. B. htttp-Nachrichten) und eine Netzwerkkarte sendet. Jetzt könnte der Flaschenhals dieser Netzwerkmanager sein. Ich möchte mehr über die Architektur des Systems wissen:)
Ich war vor ein paar Monaten in einer ähnlichen Situation. Obwohl es viele Faktoren gibt, die wir benötigen, um Ihnen zu sagen, welches die geringere Leistung verursacht, können Sie versuchen, mit einer mirco-Instanz der EC2-Instanz zu versuchen, E-Mails zu senden.
Das hat in meinem Fall gut funktioniert, und es war eine geeignete Lösung, als ich an der Webanwendung arbeitete.
Die Task ist weder CPU-gebunden noch IO-gebunden. Die Task fordert SES auf, eine E-Mail zu senden (mit begrenzten Daten oder IO) und wartet dann. Verwenden Sie also die größte Anzahl von Threads, die Sie für den verfügbaren Arbeitsspeicher verwenden können.
Wie kommentiert, das ist ein I / O-Problem, weil Sie eine gute Anzahl von Jobs mit infra / Bandbreite Größe finden müssen
Verwenden Sie ein Warteschlangenmuster,
Beispiel:
1 - Verteilen Sie eine Zustellungs-E-Mail
2 - "N" Jobs versenden die E-Mail
Tags und Links c# multithreading performance amazon-web-services producer-consumer