C#同时运行多个异步任务

时间:2017-09-23 13:43:04

标签: c# parsing asynchronous task httpclient

我对异步任务不熟悉。

我有一个功能,可以获取学生ID并从特定的大学网站上删除所需的ID。

# open file
file = open("filename", "r")

# for each line the file 'filename'
for line in file:

    # split the line in between spaces:
    words = line.split(" ")

    # get the columns by position:
    level = words[2]
    var_name_1 = words[4] 
    var_value_1 = words[6].split(",")[0] # get rid of ,
    # etc

    # do something here ...
    # perhaps add to a list:
    # array_value_1.append(var_value_1)

它运作正常。有时虽然我需要为很多学生运行这个功能所以我使用以下

    private static HttpClient client = new HttpClient();
    public static async Task<Student> ParseAsync(string departmentLink, int id, CancellationToken ct)
    {
        string website = string.Format(departmentLink, id);
        try
        {
            string data;
            var stream = await client.GetAsync(website, ct);
            using (var reader = new StreamReader(await stream.Content.ReadAsStreamAsync(), Encoding.GetEncoding("windows-1256")))
                data = reader.ReadToEnd();

            //Parse data here and return Student.
        } catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

我将任务存储在一个数组中以便稍后等待它们。

只要学生数量介于(0,~600?)之间,它也可以很好地随机运行。 然后对于尚未解析的其他每个学生抛出任务被取消

请记住,我从不使用取消令牌。

我需要在这么多学生身上运行这个功能,它可以完全达到~9000异步任务。那么发生了什么?

2 个答案:

答案 0 :(得分:3)

当您在如此短的时间内排队9000个请求时,您基本上是在网站上创建拒绝服务攻击。这不仅会导致您的错误,而且还会导致网站崩溃。最好将并发请求的数量限制为更合理的值(比如30)。虽然可能有几种方法可以做到这一点,但我想到的是:

private async Task Test()
{
  var tasks = new List<Task>();
  for (int i = ids.first; i <= ids.last; i++)
  {
    tasks.Add(/* Do stuff */);
    await WaitList(tasks, 30);
  }
}

private async Task WaitList(IList<Task> tasks, int maxSize)
{
  while (tasks.Count > maxSize)
  {
    var completed = await Task.WhenAny(tasks).ConfigureAwait(false);
    tasks.Remove(completed);
  }
}

其他方法可能会使用.Net类(如BlockingCollection

)来利用生产者/消费者模式

答案 1 :(得分:0)

这是我根据@erdomke代码最终得到的结果:

    public static async Task ForEachParallel<T>(
      this IEnumerable<T> list, 
      Func<T, Task> action, 
      int dop)
    {
        var tasks = new List<Task>(dop);
        foreach (var item in list)
        {
            tasks.Add(action(item));

            while (tasks.Count >= dop)
            {
                var completed = await Task.WhenAny(tasks).ConfigureAwait(false);
                tasks.Remove(completed);
            }
        }

        // Wait for all remaining tasks.
        await Task.WhenAll(tasks).ConfigureAwait(false);
    }

    // usage
    await Enumerable
        .Range(1, 500)
        .ForEachParallel(i => ProcessItem(i), Environment.ProcessorCount);