gpt4 book ai didi

c# - 在C#中使用async/await和httpclient进行多线程

转载 作者:行者123 更新时间:2023-12-03 05:45:59 25 4
gpt4 key购买 nike

我编写了一个控制台应用程序来下载YouTube预览图像。但是我认为该程序是同步运行的,而不是异步运行的。我做错了什么,如何使用异步/等待方式从Web进行多次加载文件?

using System;
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;


namespace YoutubePreviewer
{
class Node
{
public string Path { get; private set; }
public string Title { get; private set; }
public string Source { get; private set; }
public string Id { get; private set; }
public Previews Previews { get; set; }

public Node(string p, string t, string s, string i)
{
Path = p;
Title = t;
Source = s;
Id = i;
}

}

class Previews
{
public string[] Urls { get; private set; }


public static Previews Get(Node n)
{
string[] resolutions = {"default", "hqdefault", "mqdefault", "maxresdefault"};
for (int i = 0; i < resolutions.Length; i++)
{
string end = resolutions[i] + ".jpg";
resolutions[i] = "https://img.youtube.com/vi/" + n.Id + "/" + resolutions[i] + ".jpg";
}
Previews pr = new Previews();
pr.Urls = resolutions;
return pr;
}
}

static class Operations
{
public static async Task<string> DownloadUrl(string address)
{
HttpClient http = new HttpClient();
return await http.GetStringAsync(address);
}

public static async Task<Node> Build(string url)
{
var source = await Operations.DownloadUrl(url);
var title = Regex.Match(source, "<title>(.*)</title>").Groups[1].Value;
var id = Regex.Match(url, @"watch\?v=(.+)").Groups[1].Value;
Node node = new Node(url, title, source, id);
node.Previews =await Task<Previews>.Factory.StartNew(()=>Previews.Get(node);
return node;
}

public static async Task WriteToDisk(Node n, string path = "C:/Downloads")
{
Console.WriteLine($"Starting downloading {n.Path} previews");
var securedName = string.Join("_", n.Title.Split(Path.GetInvalidFileNameChars()));

Directory.CreateDirectory(Path.Combine(path, securedName));
HttpClient http = new HttpClient();
foreach (var preview in n.Previews.Urls)
{
try
{
var arr = await http.GetByteArrayAsync(preview);
await Task.Delay(100);
string name = preview.Substring(preview.LastIndexOf("/") + 1);
using (FileStream fs = new FileStream(Path.Combine(path, securedName, name), FileMode.Create,
FileAccess.ReadWrite))
{
await fs.WriteAsync(arr, 0, arr.Length);
}
}
catch (Exception e)
{
Console.WriteLine($"Can't download and save preview {preview}");
Console.WriteLine(e.Message);
Console.WriteLine(new string('*', 12));
}
Console.WriteLine($"{preview} is saved!");
}

}

public static async Task Load(params string[] urls)
{

foreach (var url in urls)
{
Node n = await Build(url);
await WriteToDisk(n);

}
}
}

class Program
{
static void Main(string[] args)
{

Task t= Operations.Load(File.ReadAllLines("data.txt"));

Task.WaitAll(t);

Console.WriteLine("Done");
Console.ReadKey();


}


}
}

最佳答案

您的代码正在下载URL,并将它们一次写入磁盘。它异步运行,但串行运行。

如果要使其异步并发运行,则应使用类似Task.WhenAll的方法:

public static async Task LoadAsync(params string[] urls)
{
var tasks = urls.Select(url => WriteToDisk(Build(url)));
await Task.WhenAll(tasks);
}

(此代码假定 Build是应该使用的同步方法)。

还有一些无关的问题跳出来:
  • node.Previews =await Task<Previews>.Factory.StartNew(()=>Previews.Get(node);毫无意义地将琐碎的工作发送到线程池。应该是node.Previews = Previews.Get(node);
  • 这意味着Operations.Build不必是async,实际上也不必是。
  • 您应该使用HttpClient的单个共享实例,而不是为每个请求创建一个新实例。
  • Task.WaitAll(t);很奇怪。可以只是t.Wait();
  • await Task.Delay(100);也很不寻常。
  • 关于c# - 在C#中使用async/await和httpclient进行多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41513397/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com