Ich habe einige verschachtelte Async-Methoden aufrufen einander und es ist verwirrend. Ich versuche, ein Projekt zu konvertieren, das die Dateien in einem asynchronen Download herunterlädt. Auf dem Klick auf den Download-Button ist dies die Methode ausgelöst:Verschachtelte Async-Download - Async innerhalb von Async
private async void enableOfflineModeToolStripMenuItem_Click(object sender, EventArgs e)
{
for(int i = 0; i < _playlists.Count; i++)
{
DoubleDimList.Add(new List<String>());
for(int j = 0; j < 5; j++)
{
string sMp3 = IniReadValue(_playlists[i], "Track " + j);
DoubleDimList[i].Add(sMp3);
}
await Task.Run(() => _InetGetHTMLSearchAsyncs(DoubleDimList[i]));
}
}
Es schafft eine 2d List
, die am Ende wie dieses DoubleDimList[3][20]
aussieht. Am Ende von jedem sublist
mache ich einen async
Download, wie Sie sehen können. Das Verfahren sieht wie folgt aus
private async Task _InetGetHTMLSearchAsyncs(List<string> urlList)
{
foreach (var url in urlList)
{
await Task.Run(() => _InetGetHTMLSearchAsync(url));
}
}
die _InetGetHTMLSearchAsync
Methode sieht wie folgt aus und ist hier, wo es schwierig wird
private async Task _InetGetHTMLSearchAsync(string sTitle)
{
Runs++;
if (AudioDumpQuery == string.Empty)
{
//return string.Empty;
}
string sResearchURL = "http://www.audiodump.biz/music.html?" + AudioDumpQuery + sTitle.Replace(" ", "+");
try
{
using (var client = new WebClient())
{
client.Headers.Add("Referer", @"http://www.audiodump.com/");
client.Headers.Add("user-agent", "Mozilla/5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14(KHTML, like Gecko) Version/7.0.3 Safari/7046A194A");
client.DownloadStringCompleted += Client_DownloadStringCompleted;
await Task.Run(() => client.DownloadStringAsync(new Uri(sResearchURL)));
}
}
catch (Exception ex)
{
Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace);
Console.WriteLine("Runs: " + Runs);
return;
}
}
Auf Client_DownloadStringCompleted
gibt es eine weitere async
Methode aufgerufen. Hier ist es
private async void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string[] sStringArray;
string aRet = e.Result;
string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline);
if (aTable != null)
{
string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\"");
if (aInfos != null)
{
for (int i = 0; i < 1; i++)
{
sStringArray = aInfos[i].Split('*');
sStringArray[0] = sStringArray[0].Replace("'", "'");
aLinks.Add(sStringArray[0]);
}
await Task.Run(() => DownloadFile(aLinks[FilesDownloaded]));
}
}
}
Von dort, Überraschung! Ein weiterer Anruf async
.
private async Task DownloadFile(string url)
{
try
{
using (var client = new WebClient())
{
client.Headers.Add("Referer", @"http://www.audiodump.biz/");
client.Headers.Add("user-agent", "Mozilla/5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14(KHTML, like Gecko) Version/7.0.3 Safari/7046A194A");
client.DownloadFileCompleted += Client_DownloadFileCompleted;
await Task.Run(() => client.DownloadFileTaskAsync(url, mp3Path + "\\" + count + ".mp3"));
}
}
catch (Exception Ex)
{
Console.WriteLine("File download error: " + Ex.StackTrace);
}
}
Nun ist der erste Teil nach der Gründung des 2d List
ist die Download-Links der mp3s abzurufen. Der zweite Teil ist das Herunterladen der mp3, sobald eine gültige URL
bereitgestellt wurde. Es funktioniert aber auf eine bizarre Weise. Anstatt die Datei normal herunterzuladen (1., 2., 3., ...), lädt sie die Dateien (1., 5., 8. usw.) nach dem Zufallsprinzip herunter.
Es ist mein erster gehen für async
Download und Junge, ich bin schon weit von meinen Grenzen.
Wo mache ich das kaputt? Und die Hauptfrage, wird das jemals so funktionieren, wie es funktionieren soll?
Es gibt viel zu viel Code hier, und doch nicht genug. Bitte stellen Sie eine gute [mcve] bereit, die Ihr Problem zuverlässig reproduziert. In der Zwischenzeit werde ich darauf hinweisen, dass die Verwendung von 'Task.Run()' zum Ausführen von 'async'-Methoden im Allgemeinen sinnlos ist. Rufen Sie einfach die Async-Methode direkt auf und warten Sie auf das zurückgegebene Task-Objekt. Sie können eine Gruppe von Async-Aufrufen sammeln, indem Sie die zurückgegebene Task als "IEnumerable" darstellen und dann mit "await Task.WhenAll (...)" auf die gesamte Sammlung warten. –
Wenn Sie die vorhandenen Referenzen für 'async' /' erwarten' sorgfältiger studieren und gute Idiome verwenden, wette ich, dass die meisten Ihrer Probleme einfach verschwinden würden.Beachten Sie jedoch Folgendes: Wenn Sie mehrere Operationen asynchron ausführen, ist es nicht überraschend, dass sie in einer anderen Reihenfolge abgeschlossen werden als in der sie gestartet werden. Das ist _why_ Sie verwenden asynchrone Operationen; Ansonsten können Sie sie auch synchron nacheinander ausführen. –
Sie müssen Ihre asynchronen Methoden nicht in eine Task.Run einbinden. Es wird nicht benötigt und es macht Ihren Code schwieriger zu lesen. Sie können nur warten, bis die Aufgabe Async-Methoden zurückgibt. Der Grund für die unterschiedliche Reihenfolge der Ausführung liegt auch darin, dass Sie den Download in einer Task.Run auslösen, die den Download startet. Dann wird die Methode zurückgegeben und der nächste Download gestartet. Die Reihenfolge, in der das abgeschlossene Ereignis ausgelöst wird, hängt von der Anforderungszeit selbst ab. Wenn Sie die Reihenfolge wirklich beibehalten möchten, sollten Sie stattdessen DownloadStringTaskAsync verwenden. Dadurch wird eine Aufgabe zurückgegeben, auf die Sie für das Ergebnis warten können. –