在控制台应用程序中等待异步操作结束时,如何避免出现 Thread.Sleep(Int32.MaxValue)?

发布于 2024-11-30 17:51:46 字数 771 浏览 2 评论 0原文

我有以下代码,它将异步下载文件到我的硬盘驱动器,向控制台喊出当前进度并最终以告别消息退出:

webClient.DownloadProgressChanged.Add(fun args ->
      if (currentPercentage < args.ProgressPercentage) then
        Console.WriteLine(args.ProgressPercentage.ToString() + "%")

      currentPercentage <- args.ProgressPercentage
  )

webClient.DownloadFileCompleted.Add(fun args ->
  Console.WriteLine("Download finished!")
  Environment.Exit 0
)

webClient.DownloadFileAsync(new Uri(url_to_download),  file_name)

Thread.Sleep Int32.MaxValue

不过,我想知道是否有更优雅的方式来实现这无需在主线程中诉诸“永远休眠”,让程序通过 Environment.Exit() 结束。我对使用 Environment.Exit() 没有偏见,但如果可能的话,我想避免它!我能想到避免这种情况的唯一方法是生成一个新线程,然后等待它死亡,但这看起来确实很麻烦。有更简单的方法来实现这一点吗?

I have the following code that will download a file asynchronously to my hard-drive, shouting to the console the current progress and quitting with a goodbye message in the end:

webClient.DownloadProgressChanged.Add(fun args ->
      if (currentPercentage < args.ProgressPercentage) then
        Console.WriteLine(args.ProgressPercentage.ToString() + "%")

      currentPercentage <- args.ProgressPercentage
  )

webClient.DownloadFileCompleted.Add(fun args ->
  Console.WriteLine("Download finished!")
  Environment.Exit 0
)

webClient.DownloadFileAsync(new Uri(url_to_download),  file_name)

Thread.Sleep Int32.MaxValue

I was wondering, though, whether there could be any more elegant way of achieving this without having to resort to "sleeping forever" in the main thread, having the program end though an Environment.Exit(). I have no prejudice towards using Environment.Exit() but I'd like to avoid it, if possible! The only way I can think of avoiding this would be to spawn a new thread and then waiting for it to die, but that does seem cumbersome. Any simpler way to accomplish this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

并安 2024-12-07 17:51:46

您可以像这样使用 ResetEvent:

webClient.DownloadProgressChanged += (f,a) => ...
AutoResetEvent resetEvent = new AutoResetEvent(false);
webClient.DownloadFileCompleted += (f, a) => resetEvent.Set();
webClient.DownloadDataAsync(new Uri(url_to_download), file_name);
resetEvent.WaitOne();
Console.WriteLine("Finished");

You can use a ResetEvent like this:

webClient.DownloadProgressChanged += (f,a) => ...
AutoResetEvent resetEvent = new AutoResetEvent(false);
webClient.DownloadFileCompleted += (f, a) => resetEvent.Set();
webClient.DownloadDataAsync(new Uri(url_to_download), file_name);
resetEvent.WaitOne();
Console.WriteLine("Finished");
橘虞初梦 2024-12-07 17:51:46

只需使用 waithandle 派生类(如 mutex 来发出信号)你已经准备好关门了。在下载完成的方法中发出信号,并在应用程序结束时等待它。当它发出信号时,您的应用程序将自然退出。

simply use a waithandle derived class like the mutex to signal you're ready to close down. signal it in your download completed method and wait for it at the end of your app. as it becomes signalled your app will exit naturally.

伴梦长久 2024-12-07 17:51:46

如果您是反应式扩展库(Rx)的粉丝,那么这个过程可以根据可观察的方式进行建模,例如:

    public static IObservable<int> DownloadURL(string url,string fname)
    {
        return Observable.Defer(() =>
        {
            var sub = new Subject<int>();
            var wc = new WebClient();
            wc.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
            {
                sub.OnNext(e.ProgressPercentage);
                if (e.ProgressPercentage == 100)
                    sub.OnCompleted();
            };
            wc.DownloadFileAsync(new Uri(url), fname);
            return sub;
        });
    }

    public static void Main(string[] str)
    {
        foreach (var i in DownloadURL("http://www.google.com", "g:\\google.html").DistinctUntilChanged().ToEnumerable())
            Console.WriteLine(i);
    }

In case you are a fan of the Reactive extensions library (Rx), then this process can be modeled in terms of observable like:

    public static IObservable<int> DownloadURL(string url,string fname)
    {
        return Observable.Defer(() =>
        {
            var sub = new Subject<int>();
            var wc = new WebClient();
            wc.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
            {
                sub.OnNext(e.ProgressPercentage);
                if (e.ProgressPercentage == 100)
                    sub.OnCompleted();
            };
            wc.DownloadFileAsync(new Uri(url), fname);
            return sub;
        });
    }

    public static void Main(string[] str)
    {
        foreach (var i in DownloadURL("http://www.google.com", "g:\\google.html").DistinctUntilChanged().ToEnumerable())
            Console.WriteLine(i);
    }
人海汹涌 2024-12-07 17:51:46

在 C# 中,您可以为 WebClient 编写一个扩展方法,等待下载完成,同时仍然推送更新事件:

static class WebClientEx {
    public static void DownloadSemiSync(this WebClient webClient, Uri address, string filename) {
        var evt = new AutoResetEvent(false);
        webClient.DownloadFileCompleted += (s, e) => evt.Set();
        webClient.DownloadFileAsync(address, filename);
        evt.WaitOne();
    }
}

这将允许您定义您想要的任何进度事件,然后将其用作同步函数,从而减少您的 main代码如下:

    static void Main() {
        var webClient = new WebClient();
        webClient.DownloadProgressChanged += (s, args) => {..};
        webClient.DownloadSemiSync(new Uri("http://.."), "test.bin");
        Console.WriteLine("DownloadFinished");
    }

抛出所有事件,但然后等待退出。

In C# you could write an extension method for WebClient that waits for the download to complete, while still pitching update events:

static class WebClientEx {
    public static void DownloadSemiSync(this WebClient webClient, Uri address, string filename) {
        var evt = new AutoResetEvent(false);
        webClient.DownloadFileCompleted += (s, e) => evt.Set();
        webClient.DownloadFileAsync(address, filename);
        evt.WaitOne();
    }
}

This'd allow you to define whatever progress event you want on it and then use it as a synchronous function, reducing your main code to this:

    static void Main() {
        var webClient = new WebClient();
        webClient.DownloadProgressChanged += (s, args) => {..};
        webClient.DownloadSemiSync(new Uri("http://.."), "test.bin");
        Console.WriteLine("DownloadFinished");
    }

Throws all the events, but then waits to exit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文