Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C中异步执行多个任务# 环境 视窗7 Visual Studio C# 我想做什么_C#_Asynchronous - Fatal编程技术网

在C中异步执行多个任务# 环境 视窗7 Visual Studio C# 我想做什么

在C中异步执行多个任务# 环境 视窗7 Visual Studio C# 我想做什么,c#,asynchronous,C#,Asynchronous,我正在尝试建立一个应用程序来评估公司的产品。为了安全起见,以下描述在某种程度上是抽象的 此应用程序所做的是更改产品中的某个参数,并查看产品的某个值是如何更改的。所以我需要做两件事 按一定间隔更改参数 以一定间隔在文本框中显示值 图表是这样的 应重复执行这些任务,直到按下“取消”按钮 UI具有以下控件: 按钮1:开始按钮 按钮2:取消按钮 textbox1:显示从设备获取的值 这是我写的代码 public partial class Form1 : Form { public For

我正在尝试建立一个应用程序来评估公司的产品。为了安全起见,以下描述在某种程度上是抽象的

此应用程序所做的是更改产品中的某个参数,并查看产品的某个值是如何更改的。所以我需要做两件事

  • 按一定间隔更改参数
  • 以一定间隔在文本框中显示值
  • 图表是这样的

    应重复执行这些任务,直到按下“取消”按钮

    UI具有以下控件:

    • 按钮1:开始按钮
    • 按钮2:取消按钮
    • textbox1:显示从设备获取的值
    这是我写的代码

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    
        CancellationTokenSource cts = new CancellationTokenSource();
    
        private async void button1_Click(object sender, EventArgs e)
        {
           
            await Task1();
            await Task2();
     
        }
    
    
        private async Task Task1()
        {
            while (!cts.IsCancellationRequested)
            {
                Thread.Sleep(500);
                ChangeParameter(0);
                Thread.Sleep(1000);
                ChangeParameter(10);
                Thread.Sleep(500);
                ChangeParameter(0);
            }
        }
    
        private void ChangeParameter(double param)
        {
            // change device paremeter
            Console.WriteLine("devicep parameter changed : " + param);
        }
    
        private async Task Task2()
        {
            while (!cts.IsCancellationRequested)
            {
                Thread.Sleep(100);
                int data = GetDataFromDevice();
                UpdateTextBoxWithData(data);
            }
    
            cts.Token.ThrowIfCancellationRequested();
        }
    
        private int GetDataFromDevice()
        {
            //pseudo code
            var rnd = new Random();
            return rnd.Next(100);
        }
    
        private void UpdateTextBoxWithData(int data)
        {
            textBox1.AppendText(data.ToString() + "\n");
            // debug
            Console.WriteLine("data : " + data);
        }
    
    
        private void button2_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }
    
    
    }
    
    问题 但是,此代码中有两个问题

  • 用户界面冻结
  • Task2从未执行过
  • 第二个问题源自
    wait
    ,因为它逐个执行任务。我可以使用
    Task.Run()
    ,但这不允许向textBox添加值,因为它与UI线程不同


    如何解决这些问题?任何帮助都将不胜感激。

    问题在于您没有在任务中使用
    wait
    ,因此它们会同步执行

    您应该使用类似的方法来保持UI的响应性(注意这不是生产代码,我只是展示一个想法):

    基本上,当您需要在后台运行某些东西时,应该将其包装在
    Task.run()
    中,然后
    等待结果。简单地将
    async
    添加到您的方法不会使此方法异步


    为了使您的代码更清晰,我建议您将
    GetDataFromDevice
    ChangeParameter
    等方法移动到服务层。另外,请查看
    IProgress
    ,因为注释建议根据某些流程的进度更新UI。

    问题在于您没有在任务中使用
    wait
    ,因此它们会同步执行

    您应该使用类似的方法来保持UI的响应性(注意这不是生产代码,我只是展示一个想法):

    基本上,当您需要在后台运行某些东西时,应该将其包装在
    Task.run()
    中,然后
    等待结果。简单地将
    async
    添加到您的方法不会使此方法异步


    为了使您的代码更清晰,我建议您将
    GetDataFromDevice
    ChangeParameter
    等方法移动到服务层。另外,请查看
    IProgress
    ,评论建议您根据某些流程的进度更新UI。

    此代码存在许多问题:

  • async/await
    不会自动使代码异步。它允许您等待已经异步的操作的结果。如果要在后台运行尚未异步的内容,则需要使用Task.run或类似的方法启动任务
  • wait
    将执行返回到原始同步上下文。在本例中,UI线程。通过使用Thread.Sleep,您正在冻结UI线程
  • 您不能从其他线程更新UI,这也适用于任务。您可以使用IProgress界面来报告进度。很多BCL类都使用这个接口,就像CancellationToken一样
  • Maxim Kosov已经清理了代码,并演示了如何正确使用
    async/await
    和Task.Run,所以我只介绍如何使用及其实现

    IProgress用于使用该方法公开进度更新。它的默认实现Progress在UI线程上引发事件和/或调用传递给其构造函数的
    操作。特别是,在创建类时捕获的同步上下文上

    您可以在构造函数或按钮单击事件中创建进度对象,例如

    private async void button1_Click(object sender, EventArgs e)
    {
        var progress=new Progress<int>(data=>UpdateTextBoxWithData(data));
    
        //...
        //Allow for cancellation of the task itself
        var token=cts.Token;
        await Task.Run(()=>MeasureInBackground(token,progress),token);
    
    }
    
    
    private async Task MeasureInBackground(CancellationToken token,IProgress<int> progress)
    {
        while (!token.IsCancellationRequested)
        {
            await Task.Delay(100,token);
    
            int data = GetDataFromDevice(); 
            progress.Report(data);
        }
    }
    
    在这里,我只是懒洋洋地返回一个
    元组。专用的进度类在生产代码中更合适

    使用动作的优点是不需要管理事件处理程序,并且对象是异步方法的本地对象。清理由.NET本身执行

    如果设备API提供真正的异步调用,则不需要
    Task.Run
    。这意味着您不必在tigh循环中浪费任务,例如:

    private async Task MeasureInBackground(CancellationToken token,IProgress<Tuple<int,string>> progress)
    {
        while(!token.IsCancellationRequested)
        {
            await Task.Delay(100, token);
            int data = await GetDataFromDeviceAsync(); 
            progress.Report(Tuple.Create(data,"Working"));
        }
        progress.Report(Tuple.Create(-1,"Cancelled!"));
    }
    

    此代码存在许多问题:

  • async/await
    不会自动使代码异步。它允许您等待已经异步的操作的结果。如果要在后台运行尚未异步的内容,则需要使用Task.run或类似的方法启动任务
  • wait
    将执行返回到原始同步上下文。在本例中,UI线程。通过使用Thread.Sleep,您正在冻结UI线程
  • 您不能从其他线程更新UI,这也适用于任务。您可以使用IProgress界面来报告进度。很多BCL类都使用这个接口,就像CancellationToken一样
  • Maxim Kosov已经清理了代码,并演示了如何正确使用
    async/await
    和Task.Run,所以我只介绍如何使用及其实现

    IProgress用于使用该方法公开进度更新。它的默认实现Progress在UI线程上引发事件和/或调用传递给其构造函数的
    操作。特别是,在创建类时捕获的同步上下文上

    您可以在构造函数或按钮单击事件中创建进度对象,例如

    private async void button1_Click(object sender, EventArgs e)
    {
        var progress=new Progress<int>(data=>UpdateTextBoxWithData(data));
    
        //...
        //Allow for cancellation of the task itself
        var token=cts.Token;
        await Task.Run(()=>MeasureInBackground(token,progress),token);
    
    }
    
    
    private async Task MeasureInBackground(CancellationToken token,IProgress<int> progress)
    {
        while (!token.IsCancellationRequested)
        {
            await Task.Delay(100,token);
    
            int data = GetDataFromDevice(); 
            progress.Report(data);
        }
    }
    
    在这里,我只是懒洋洋地返回一个
    元组。专用的进度类在生产代码中更合适

    美国的优势
    private async Task MeasureInBackground(CancellationToken token,IProgress<Tuple<int,string>> progress)
    {
        while(!token.IsCancellationRequested)
        {
            await Task.Delay(100, token);
            int data = await GetDataFromDeviceAsync(); 
            progress.Report(Tuple.Create(data,"Working"));
        }
        progress.Report(Tuple.Create(-1,"Cancelled!"));
    }
    
    await MeasureInBackground(token,progress);
    
    private async Task Task1()
    {
        await Task.Run(() =>
        {
            while (!cts.IsCancellationRequested)
            {
                Thread.Sleep(500);
                ChangeParameter(0);
                Thread.Sleep(1000);
                ChangeParameter(10);
                Thread.Sleep(500);
                ChangeParameter(0);
            }
        }
    }
    
    private async void button1_Click(object sender, EventArgs e)
    {
        await Task1();
        await Task2();
    }
    
    private async void button1_Click(object sender, EventArgs e)
    {
        Task t1 = Task1();
        Task t2 = Task2();
        await Task.WhenAll(new[] { t1, t2 });
    }
    
    // await Task.Run(() => LooongOperation(), token);
    await Task.Factory.StartNew(() => LooongOperation(), token, TaskCreationOptions.LongRunning, TaskScheduler.Default);