程序在没有调试器的情况下运行不同

Program runs differently without debugger

我有一个程序 (.NET 5) 使用 WebClient.DownloadFile 同时下载一堆文件 (1k+)调试和发布模式下的文件;但是当运行退出调试器时,它无法下载超过 50% 的文件。

所有线程都在程序结束前完成,因为它们是前台线程。

程序代码为:

using System;
using System.IO;
using System.Net;
using System.Threading;

namespace Dumper
{
    internal sealed class Program
    {
        private static void Main(string[] args)
        {
            Directory.CreateDirectory(args[1]);

            foreach (string uri in File.ReadAllLines(args[0]))
            {
                string filePath = Path.Combine(args[1], uri.Split('/')[^1]);

                new Thread((param) =>
                {
                    (string path, string url) = ((string, string))param!;
                    using WebClient webClient = new();

                    try
                    {
                        webClient.DownloadFile(new Uri(url.Replace("%", "%25")), path);

                        Console.WriteLine($"{path} has been successfully download.");
                    }
                    catch (UriFormatException)
                    {
                        throw;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"{path} failed to download: {e}");
                    }
                }).Start((filePath, uri));
            }
        }
    }
}

您的问题与调试无关,但一般而言,您的代码存在很多问题。这是一个更明智的方法,等待所有下载完成。

注意:您也可以使用 Task.WhenAll,但是我选择使用 TPL 数据流 ActionBlock 以防您需要管理并行度

给定

private static readonly HttpClient _client = new();

private static string _basePath;

private static async Task ProcessAsync(string input)
{
   try
   {
      var uri = new Uri(Uri.EscapeUriString(input));

      var filePath = Path.Combine(_basePath, input.Split('/')[^1]);

      using var result = await _client
         .GetAsync(uri)
         .ConfigureAwait(false);

      // fail fast
      result.EnsureSuccessStatusCode();

      await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 1024 * 1024, FileOptions.Asynchronous);

      await using var stream = await result.Content
         .ReadAsStreamAsync()
         .ConfigureAwait(false);

      await stream.CopyToAsync(fileStream)
         .ConfigureAwait(false);

      Console.WriteLine($"Downloaded : {uri}");

   }
   catch (Exception e)
   {
      Console.WriteLine(e);
   }
}

用法

private static async Task Main(string[] args)
{
   var file = args.ElementAtOrDefault(0) ?? @"D:\test.txt";
   _basePath = args.ElementAtOrDefault(1) ?? @"D:\test";

   Directory.CreateDirectory(_basePath);

   var actionBlock = new ActionBlock<string>(ProcessAsync,new ExecutionDataflowBlockOptions()
   {
      EnsureOrdered = false,
      MaxDegreeOfParallelism = -1 // set this if you think the site is throttling you
   });

   foreach (var uri in File.ReadLines(file))
      await actionBlock.SendAsync(uri);

   actionBlock.Complete();
   // wait to make sure everything is completed
   await actionBlock.Completion;

}