【发布时间】:2019-04-26 14:48:57
【问题描述】:
我们有一个基于查询字符串进行图像处理然后呈现结果的服务器。结果也会被缓存 90 天。由于复杂性,一些操作可能需要 6-7 秒。
我们列出了我们的一些产品的市场最近减少了它们在获取图像时的超时时间到一个较低的值,导致任何给定 Feed 中的大多数商品由于(他们的错误消息)“图像超时”而第一次失败。当我们重新提交提要时,就没有这样的问题了,因为我们的图像服务器现在已经缓存了图像。
请不要建议要求市场更改他们的超时时间。他们非常不灵活和不合作。另外,请不要建议使用更强大的图像服务器。它实际上是一个巨大的农场,不受我的团队控制。
这让我只有一个选择。在将提要发送到市场之前,我需要“准备好缓存”。问题是一个提要最多可以包含 5000 个项目,每个项目至少有 2 张图像。这意味着 10,000 张图片。
我正在使用HEAD 调用,因为我们不需要返回给我们的图像。我曾尝试在.Net Framework 中使用WebRequest 甚至Socket,在异步Task 中调用(使用Task.Run()`),但CLR 一次只能启动大约20 个任务。由于平均而言,每张图像大约需要 4 秒(有些长达 6-7 秒,有些只需要 1 秒),因此您需要 10,000 / 20 = 500 * 4 秒 = 2000 秒 = 33 1/3 分钟,这不是在我们发送提要之前,我们可以等待。
由于我们实际上并不需要来自图像服务器的回复,因此我尝试对图像服务器使用异步请求,并在创纪录的时间内通过foreach,但我发现,使用该异步请求我不能保证调用会在启动所有任务的代码完成时触发,所以这无济于事。
我们使用 AWS,所以我考虑使用 Lambda,但这会增加额外的复杂性和费用,但那里的大规模并行能力听起来可以解决问题。
我该如何解决这个问题?
测试服务器
public class HomeController : Controller {
private Random random;
public HomeController() {
random = new Random(DateTime.UtcNow.Millisecond);
}
public ActionResult Index(string url) {
var wait = random.Next(1, 70);
Thread.Sleep(wait * 100);
return Content(wait + " : " + url);
}
}
测试客户端
class Program {
static void Main(string[] args) {
var tasks = new List<Task>();
for (var i = 0; i < 200; i++) {
Console.WriteLine(i.ToString());
var task = SendRequest("http://test.local.com/Home/Index?url=" + i);
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
private static async Task SendRequest(string url) {
try {
var myWebRequest = WebRequest.Create(url);
myWebRequest.Method = "HEAD";
var foo = await myWebRequest.GetResponseAsync();
//var foo = myWebRequest.GetResponseAsync();
//var foo = myWebRequest.GetResponse();
foo.Dispose();
}
catch { }
}
}
【问题讨论】:
-
连接池限制可能吗? (适用于 WebRequest,但不适用于 Socket。)CLR 肯定很乐意启动更多任务。
-
哇!乔恩斯基特。好吧,如果有人可以帮助我,我知道你可以。我跑了
ThreadPool.GetMaxThreads,得到了 32K 和 1000,所以似乎有很多可用的工人和 IO 连接。如何让 CLR 使用它们? -
如果不知道您当前的代码是什么样的,很难说要更改什么。请提供minimal reproducible example。 (理想情况下也有一个小型 Web 服务器,只使用 HttpListener - 可以模拟延迟,并计算并发请求。)
-
试试
ThreadPool.SetMinThreads(100, 100);看看是否有什么不同。 -
从长远来看,图像服务器获得接受 URL 列表并缓存它们的功能可能会更有效。作为一项低优先级的工作,它可以以最小的开销完成它,并且希望足够快以满足您团队的需求。用大量并发请求轰炸服务器可能与 DOS 攻击具有相同的效果。 ??????
标签: c# multithreading webrequest