2016-03-23 8 views
0

Ich sammle Daten von MongoDB der folgenden Methode:Wie kann der Durchsatz durch Parallelisierung des Datenbankzugriffs verbessert werden?

public IEnumerable<TOutput> GetMatchingJobs<TOutput>(JobInfoFilterParameters filterParameters, FetchOptions<JobInfoRecord, TOutput> fetchOptions) 
{ 
    var filter = CreateFilterDefinition(filterParameters); 
    var options = CreateFindOptions(fetchOptions, false); 

    return MongoDatabaseStorageService.WithRecords<JobInfoRecord, List<TOutput>> 
    (collection => collection.FindAsync(filter, options).Result.ToListAsync().Result); 
} 

/// <summary> 
/// Performs an operation on the database, automatically disconnecting and retrying 
/// if the database connection drops. 
/// </summary> 
/// <param name="operation"></param> 
public TResult WithRecords<T, TResult>(Func<IMongoCollection<T>, TResult> operation) 
{ 
    try { } 
    finally { _lock.EnterUpgradeableReadLock(); } 
    try 
    { 
     return WithRecordsInternal(operation); 
    } 
    finally 
    { 
     _lock.ExitUpgradeableReadLock(); 
    } 
} 

private TResult WithRecordsInternal<T, TResult>(Func<IMongoCollection<T>, TResult> operation) 
{ 
    try 
    { 
     return operation(GetCollection<T>()); 
    } 
    catch (IOException) 
    { 
     // There is an issue in mongo drivers when IOException is thrown instead of reconnection attempt. 
     // Try repeat operation, it will force mongo to try to reconnect. 
     return operation(GetCollection<T>()); 
    } 
} 

Ich wunderte mich über Asynchron-Betrieb wie FindAsync() und ToListAsync() mit .Result

Wie kann ich die Leistung zu verbessern (oder der Durchsatz durch den Datenbankzugriff Parallelisierung) mit async-await oder was ist das richtige Muster zu verwenden async correcty (wenn ich es kaputt)?

+2

Sind Sie sich bewusst, dass sich aktualisierbare Schlösser gegenseitig ausschließen? Es gibt keine Nebenläufigkeit hier. Es ist identisch mit einem X-Schloss hier. das bringt die Leute manchmal in Verlegenheit. – usr

+0

Nein, wie kann ich das beheben? – Anatoly

+0

Nicht sicher, ich weiß nicht, warum Sie eine RW-Sperre (oder ein Schloss) verwenden. – usr

Antwort

3

Sie können den Datenbankzugriffsdurchsatz mit asynchronen IOs nicht verbessern. All dies ändert die Art, wie der Anruf initiiert und abgeschlossen wird. Die exakt gleichen Daten werden über das Netzwerk übertragen.

Sie können möglicherweise den Durchsatz verbessern, indem Sie den Datenbankzugriff parallelisieren, aber unabhängig von Async-IO.

collection.FindAsync(filter, options).Result.ToListAsync().Result 

Hier werden Sie die schlimmstmögliche perf bekommen: Höhere Call Overhead durch asynchrone, dann blockiert, was wiederum teuer ist. Wenn das eine gute Idee wäre, würde die Bibliothek dieses Muster nur intern für Sie machen.

+0

Ich bin nicht sicher, ob die Bibliothek das Muster intern für mich tut. Wie kann ich das vermeiden? Kannst du mir den richtigen Weg zeigen? – Anatoly

+0

Ich bin * sicher * es * macht * es nicht und es kann nicht gemacht werden. Es gibt nichts, was Sie hier vermeiden oder gewinnen könnten. Sie können die Leistung von DB-Vorgängen nicht verbessern, indem Sie async gehen. – usr

+0

Danke, aber was ist mit dem Durchsatz durch Parallelisierung des Datenbankzugriffs? – Anatoly

0

Sie könnten gewissermaßen die Datenbankaufrufe parallelisieren, aber Sie müssen Async-Await von oben nach unten verwenden. Im Folgenden finden Sie ein Beispiel für das Erstellen einer Reihe von Async-Anrufen, das Erfassen ihrer Aufgabenversprechen und das Warten, bis alle fertig sind.

var tasks = new List<Task>(); 
tasks.Add(AsyncCall1); 
tasks.Add(AsyncCall2); 

await Task.WhenAll(tasks); 

Wenn Sie eine Async-Methode aufrufen und verwenden Sie .RESULT, Sie sofort den aufrufenden Thread verursacht Verfahren zu warten, bis die Asynchron-zu vervollständigen. Das obige ist nur ein einfaches Beispiel, um den Punkt zu vermitteln, dass Sie asynchrone Operationen parallel schalten können. Im Allgemeinen ist Async-Await ein bisschen wie ein Virus, der dazu neigt, sich über die gesamte Codebasis auszubreiten, da die besten Vorteile davon herrühren, wenn Sie es von oben bis unten verwenden. Async, das nur .Result verwendet, führt auf eine teurere Weise als die Verwendung der synchronen Aufrufe nicht wirklich etwas anderes als die gleiche Operation aus.

Eine andere mögliche Option, die Sie wollen würde, ist zu messen, die Asynchron-Anrufe an die Aufgabe Sammlung hinzufügen und dann ruft:

Task.WhenAll(tasks).Wait(); 

Dies ist der aufrufende Thread auf dem .Wait zu blockieren verursachen würde, aber die Aufgaben in die Sammlung würde parallel ablaufen, sobald alles abgeschlossen ist, würde der aufrufende Thread fortfahren. Ich persönlich würde es vorziehen, Async-Await den ganzen Weg zu verwenden, aber Sie haben möglicherweise diese Option nicht.

Diese Blogserie kann hilfreich für Sie sein. http://blog.stephencleary.com/2012/02/async-and-await.html

Verwandte Themen