【问题标题】:Using of Thread within a constructor?在构造函数中使用线程?
【发布时间】:2015-06-10 11:53:29
【问题描述】:

我是新手,正在努力学习正确的方法。

是否可以在构造函数中使用线程来避免 gui(Form) 在创建对象时冻结?我会经常重用这个类。

class Cmd
{
    protected static string parameters;
    protected HashSet<string> list_result;

    public Cmd( string parameters)
    {
        Thread Thread1 = new Thread(new ThreadStart(Process1));
        Thread1.Start();
        Thread1.Join();
    }

     private void Process1()
    {
        ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/c " + parameters);
        processStartInfo.RedirectStandardOutput = true;
        processStartInfo.RedirectStandardError = true;
        processStartInfo.CreateNoWindow = true;
        processStartInfo.UseShellExecute = false;

        Process process = Process.Start(processStartInfo);

        list_result = new HashSet<string>();
        while (!process.StandardOutput.EndOfStream)
        {
            string line = process.StandardOutput.ReadLine();
            list_result.Add(line);
        }
    }

【问题讨论】:

  • 您在此处编写代码的方式将无济于事,因为您加入了线程,在线程完成之前有效地阻塞。这真的解决了什么问题吗?
  • 我不会加入线程 - 不会加入构造函数。你至少不能使用continuation 吗?您需要使用task 而不是System.Thread,但是对于您要执行的操作,这应该没问题,恕我直言...
  • 考虑使用Task.Run 来运行您的方法,而不是单独的类。您可以在 UI 中调用 await 以异步等待其他进程完成。
  • 或者你可以使用ReadLineAsync而不是ReadLine,并且在不使用线程的情况下避免阻塞
  • 它工作正常,我只想知道这种做法是否可以接受。 join() 是必需的,因为必须在调用任何方法之前创建对象。作为建议,我会尝试 Task,因为它看起来很容易实现。

标签: c# multithreading constructor


【解决方案1】:

您甚至不需要线程。您可以使用 StreamReader 的 asynchronous methods 异步读取输入行:

    private async void button1_Click(object sender, EventArgs e)
    {
        var lines=await Process1(@"dir g:\ /s");
        var result= String.Join("|", lines);
        this.textBox1.Text = result;
    }

    private async Task<HashSet<String>>   Process1(string parameters)
    {
        var list_result = new HashSet<string>();
        ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/c " + parameters);
        processStartInfo.RedirectStandardOutput = true;
        processStartInfo.RedirectStandardError = true;
        processStartInfo.CreateNoWindow = true;
        processStartInfo.UseShellExecute = false;

        Process process = Process.Start(processStartInfo);


        while (!process.StandardOutput.EndOfStream)
        {
            string line = await process.StandardOutput.ReadLineAsync();
            list_result.Add(line);
        }
        return list_result;
    }

优点是不浪费线程,不需要任何同步代码或静态字段来传递参数和读取结果。

【讨论】:

    【解决方案2】:

    如果您希望在执行耗时的任务时避免 UI 冻结,您应该在表单中添加 BackgroundWorker 并在其事件处理程序中运行您的任务

    您可以在此处找到示例:https://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx

    您还应该考虑使用更新的 async/await 逻辑,这通常比 BackgroundWorker 更好,正如 Panagiotis Kanavos 在他的回答中提到的那样

    【讨论】:

    • Task.Runasync/await 更简单,允许组合多个异步调用、异常处理等。BackgroundWorker 仅出于兼容性原因有用
    • @Panagiotis Kanavos - 同意,这些也可以使用。
    • @Panagiotis Kanavos 为什么你说这些选项比BackgroundWorker 更容易?我发现它很容易使用,而至少async/await 看起来相当混乱。也许我只是没有阅读正确的文档。
    • @bkribbs 检查我的答案,看看如何使用async/await 完成此操作,而无需任何线程。事实上,BackgroundWorker 几乎不可能执行两个单独的异步操作(例如,下载一个文件并将其写入数据库,或者进行两次 Web 服务调用)——您需要两个单独的工作线程,或者同步执行所有操作。
    • @bkribbs:我在using Task.Run instead of BackgroundWorker 上有一个博客系列。
    猜你喜欢
    • 2015-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多