【发布时间】:2016-09-28 02:43:42
【问题描述】:
我有一些通过第三方库运行数千个 URL 的代码。有时库中的方法会挂起,这会占用一个线程。过了一会儿,所有线程都被什么都不做的进程占用了,然后它就停止了。
我使用SemaphoreSlim 来控制添加新线程,这样我就可以运行最佳数量的任务。我需要一种方法来识别运行时间过长的任务,然后杀死它们,同时从SemaphoreSlim 释放一个线程,以便可以创建一个新任务。
我正在为这里的方法苦苦挣扎,所以我制作了一些模仿我正在做的事情的测试代码。它创建的任务有 10% 的机会挂起,很快所有线程都挂起。
我应该如何检查并杀死它们?
代码如下:
class Program
{
public static SemaphoreSlim semaphore;
public static List<Task> taskList;
static void Main(string[] args)
{
List<string> urlList = new List<string>();
Console.WriteLine("Generating list");
for (int i = 0; i < 1000; i++)
{
//adding random strings to simulate a large list of URLs to process
urlList.Add(Path.GetRandomFileName());
}
Console.WriteLine("Queueing tasks");
semaphore = new SemaphoreSlim(10, 10);
Task.Run(() => QueueTasks(urlList));
Console.ReadLine();
}
static void QueueTasks(List<string> urlList)
{
taskList = new List<Task>();
foreach (var url in urlList)
{
Console.WriteLine("{0} tasks can enter the semaphore.",
semaphore.CurrentCount);
semaphore.Wait();
taskList.Add(DoTheThing(url));
}
}
static async Task DoTheThing(string url)
{
Random rand = new Random();
// simulate the IO process
await Task.Delay(rand.Next(2000, 10000));
// add a 10% chance that the thread will hang simulating what happens occasionally with http request
int chance = rand.Next(1, 100);
if (chance <= 10)
{
while (true)
{
await Task.Delay(1000000);
}
}
semaphore.Release();
Console.WriteLine(url);
}
}
【问题讨论】:
-
你不应该首先杀死任务。使用某种协作机制来中断操作,因此它可以释放它负责的信号量。不幸的是,您的问题缺乏了解您的任务实现本身所需的所有细节,但一般来说,在处理网络 I/O(例如 HTTP 请求)时,您甚至不应该有一个活动线程......您应该使用.NET 异步 API,用于您正在执行的操作。
-
“我应该怎么……杀了他们?” - 你不应该 - 杀死线程很糟糕。如果您的第三方库崩溃,那么您可能需要考虑在单独的
AppDomain中运行该库,以便您可以彻底关闭它。 -
我同意@Enigmativity,但要完全隔离,您需要一个单独的进程,而不仅仅是一个AppDomain。
-
@StephenCleary - 是的,这可能会更好,但
AppDomain应该就足够了。
标签: c# .net multithreading asynchronous