异步等待循环/数学问题

Cod*_*n64 1 c# wpf multithreading asynchronous async-await

我正在制作一个用WPF和Async/Await进行多线程练习的程序,该程序的作用是:

  1. 找到两个数字"a"和"b"之间的所有素数,并将它们吐出到名为"Prime1"的文本框中.
  2. 同时在另一个任务中,找到"c"和"d"之间的所有素数,然后将它们吐出到一个名为"Prime2"的文本框中.
  3. 窗口中的一个按钮将允许用户单击它,它将跟踪它被点击的次数,而其他两个任务找到素数,以演示异步操作.

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPF_Asynch_Project
{
    public partial class MainWindow : Window
    {
        public int ClickAmount = 0;
        public MainWindow()
        {
            InitializeComponent();
            DelegationIsAwesome();
        }

        private void Test_Click(object sender, RoutedEventArgs e)
        {
            ClickAmount++;
            MessageBox.Show("You clicked me " + ClickAmount.ToString() + " times!");
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private async void DelegationIsAwesome()
        {
            Task enumtask = new Task(() => FindPrimes(100000, 100000000));
            Task[] enumall = new Task[2];
            enumall[0] = enumtask;
            enumall[1] = new Task(() => FindPrimes2(1000, 10000));
            enumall.ToList().ForEach(t => t.Start());
            await Task.WhenAll(enumall).ConfigureAwait(false);
        }

        private void FindPrimes(long lower, long upper)
        {
            for (long i = lower; i < upper; i++)
            {

                long primeornot = 1;
                for (long q = 2; q < i; q++)
                {
                    if (i % q == 0)
                    {
                        primeornot = 0;
                    }
                }
                if (primeornot == 1)
                {
                    System.Threading.Thread.Sleep(6);
                    Prime1.Dispatcher.BeginInvoke(
                        (Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));
                }
            }
        }

        private void FindPrimes2(int lower, long upper)
        {
            for (int i = lower; i < upper; i++)
            {
                int primeornot = 1;
                for (int q = 2; q < i; q++)
                {
                    if (i % q == 0)
                    {
                        primeornot = 0;
                    }
                }
                if (primeornot == 1)
                {
                    System.Threading.Thread.Sleep(5);
                    Prime2.Dispatcher.BeginInvoke(
                        (Action)(() => { Prime2.Text += i.ToString() + ", "; }));
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我得到奇怪的结果.以下是该计划的图片:

在此输入图像描述

显然,寻找方法的输出是不正确的.但为什么它不断重复那些相同的数字呢?它有时也吐出一个等于UpperBound的数字,即使"i"永远不应该等于或大于UpperBound.

我的输出发生了什么,我该如何解决?

Jon*_*eet 6

这与async/await无关,真的.

你在BeginInvoke这里打电话:

Prime1.Dispatcher.BeginInvoke(
    (Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));
Run Code Online (Sandbox Code Playgroud)

...并且您的lambda表达式使用i,这意味着它将附加i 委托执行时的当前值.这不一定是i你打电话时的价值BeginInvoke.

如果要捕获(而不是变量),则基本上每次都需要实例化一个新变量.您也可以转换为字符串:

string textToAppend = i + ", ";
// No need for braces here...
Prime1.Dispatcher.BeginInvoke((Action)(() => Prime1.Text += textToAppend));
Run Code Online (Sandbox Code Playgroud)

因为您已textToAppend在循环内声明了变量,所以每次迭代都会创建一个捕获单独变量的委托.

您需要在两种方法中执行此操作.