我有以下多线程代码来计算Euler的数字。我是多线程编程的新手,也许我错过了一些东西。由于某种原因,countdown.Wait()不等待所有线程,而且totalSum几乎每次都不同。看起来它会跳过一些中间数。
public static class Program
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
private static CountdownEvent countDown = new CountdownEvent(threadsCount);
private static Object locker = new Object();
private static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateEulerNumber), threadIndex);
}
countDown.Wait();
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static void CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
totalSum = BigRational.Add(totalSum, sum);
stopwatch.Stop();
lock (locker)
{
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToDecimalString(40));
}
Console.WriteLine();
}
countDown.Signal();
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
答案 0 :(得分:0)
@usr提出了一个很好的观点:您最好使用http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx中详述的ConcurrentStack<T>
或ConcurrentQueue<T>
。
此外,使用Task.Factory实现算法更好,正如http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx中 Alexandra Rusina 所解释的那样。根据提到的资源,您的解决方案可能看起来像下面的内容(给您一般的想法)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
ConcurrentStack<int> cs = new ConcurrentStack<int>();
public static double YourFunction(int SomeNumber)
{
// computation of result
return result;
}
private void start_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "";
label1.Content = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{
int j = i;
var t = Task.Factory.StartNew(() =>
{
int result = YourFunctiopn(j);
this.Dispatcher.BeginInvoke(new Action(() =>
cs.Add(result ))
, null);
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});
}
}
希望这会有所帮助。 RGDS,
答案 1 :(得分:0)
您正在错误地使用CountDownEvent .CountDownEvent用于信令,您在当前程序中不需要这个。您可以使用任务执行此操作:
public class Class1
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
public static void Main1(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<Task<BigRational>> tasks = new List<Task<BigRational>>();
//Create the tasks
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
Task<BigRational> task = new Task<BigRational>((data)=>
{
return CalculateEulerNumber(data);
},threadIndex);
tasks.Add(task);
}
foreach (var task in tasks)
{
task.Start();
}
//Wait for tasks
Task.WaitAll(tasks.ToArray());
//Add the results
foreach (var task in tasks)
{
totalSum = BigRational.Add(totalSum, task.Result);
}
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static BigRational CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
stopwatch.Stop();
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToString());
}
Console.WriteLine();
return sum;
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
因此创建任务并且每个任务可以单独运行并返回单个总和。然后,您可以添加结果以创建总和。也不需要锁。