我正在制作一个用WPF和Async / Await进行多线程练习的程序,该程序的作用是:
代码如下:
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() + ", "; }));
}
}
}
}
}
然而我得到奇怪的结果。以下是该计划的图片:
显然,寻找方法的输出是不正确的。但为什么它不断重复那些相同的数字呢?它有时也吐出一个等于UpperBound的数字,即使“i”永远不应该等于或大于UpperBound。
我的输出发生了什么,我该如何解决?
答案 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
,所以每次迭代都会创建一个捕获单独变量的委托。
您需要在两种方法中执行此操作。