异步等待循环/数学问题

时间:2015-10-01 20:42:12

标签: c# wpf multithreading asynchronous async-await

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

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

    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() + ", "; }));
                    }
                }
            }
        }
    }
    

    然而我得到奇怪的结果。以下是该计划的图片:

    enter image description here

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

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

1 个答案:

答案 0 :(得分:6)

这与async / await无关,真的。

您在此处致电BeginInvoke

Prime1.Dispatcher.BeginInvoke(
    (Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));

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

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

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

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

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