ptr*_*rsc 8 c# c++ concurrency
我在Mac 2上运行类似的代码示例,一个用C++编写,另一个用C#编写.2个并行执行的简单任务(或者至少我希望它们),一个在循环中打印'+',另一个在循环中打印' - '.我期待2个样本的输出非常相似,但是我觉得它们有点不同.
C++似乎真正并行运行任务.我可以看到+ - 在每次运行时都很好地交替,但C#似乎运行一个任务一段时间,然后切换到另一个任务并运行一段时间.像这样的东西:
C++: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C# : ++++++++++---------++++++------
Run Code Online (Sandbox Code Playgroud)
我理解无法对并行线程的运行方式做出假设,我很好奇C++能够始终如一地产生如此好的结果.
谢谢你的时间!
C#:
using System;
using System.Threading.Tasks;
public class ConcurrentTasks
{
public static void Main(String[] args)
{
var task1 = Task.Run(()=>DemoTask("+"));
var task2 = Task.Run(()=>DemoTask("-"));
var res1 = task1.Result;
var res2 = task2.Result;
Console.WriteLine("\nResults:");
Console.WriteLine(res1);
Console.WriteLine(res2);
}
private static String DemoTask(String label)
{
for (int i = 0; i < 1000; i++)
{
Console.Write(label);
}
return label + " result";
}
}
// mcs ConcurrentTasks.cs
// mono ConcurrentTasks.exe
Run Code Online (Sandbox Code Playgroud)
C++:
#include <iostream>
#include <sstream>
#include <future>
using namespace std;
string demoTask(char label)
{
for (int i = 0; i < 1000; i++)
{
cout << label;
}
stringstream ss;
ss << label;
ss << " result";
return ss.str();
}
int main()
{
auto task1 = async(demoTask, '+');
auto task2 = async(demoTask, '-');
auto res1 = task1.get();
auto res2 = task2.get();
cout << endl << "Results:" << endl;
cout << res1 << endl;
cout << res2 << endl;
return 0;
}
// g++ --std=c++14 -Wall ConcurrentTasks.cpp -o ConcurrentTasks.exe
// ./ConcurrentTasks.exe
Run Code Online (Sandbox Code Playgroud)
编辑:我已经将C#示例更改为使用裸线程,结果是相同的.
C#with Thread:
using System;
using System.Threading;
public class ConcurrentTasks
{
public static void Main(String[] args)
{
var t1 = new Thread(() => DemoTask("+"));
var t2 = new Thread(() => DemoTask("-"));
t1.Start();
t2.Start();
}
private static String DemoTask(String label)
{
for (int i = 0; i < 1000; i++)
{
Console.Write(label);
}
return label + " result";
}
}
Run Code Online (Sandbox Code Playgroud)
粒度可能是一个原因.TPL可能具有调度任务的粗粒度,但C++ async实现可能具有精细的粒度.这实际上意味着C++将花费更多时间,因为只是为了处理+或者-它正在调度其中的另一个任务.
另一个原因可能是如何cout和Console已经实施的输出流.如何在屏幕上呈现某些东西?是否正在实施缓冲?你看,Console.Write可能是缓冲,然后打印一段时间后,但cout可能只是立即打印.
因此,您应该执行其他操作,而不是依赖于语言的基础I/O - 可以将该字符放在共享静态大小的数组上,共享int 为共享数组的索引(它们是原子的,不需要锁用最轻的同步原语(如读写器锁)锁定它.不,不要使用vector或Array- 因为在这种情况下,你再次依赖于你不知道的东西!
在两种情况下都使用Release版本,并使用尽可能相同的优化选项.此外,请确保您在同一台计算机上运行它们.
所以看起来 C# 的控制台影响最大。
我再次修改了 C# 示例,以便在执行 2 个任务时不使用控制台。相反,我使用共享输出字符数组。结果截然不同,非常接近 C++,尽管不那么完美和一致。
令人惊奇的是,C++ 程序在每次运行时都会生成完美的 +- 对,即使使用了 cout。C# 输出每次都略有不同,并且经常我仍然看到一个线程在下一个线程开始之前完成。我必须显着增加迭代次数,因为迭代次数较少时,任务始终按顺序运行。
这是更新的 C# 示例(注意互锁增量!):
using System;
using System.Threading;
using System.Threading.Tasks;
public class ConcurrentTasks
{
private static char[] m_out;
private static int m_index = -1;
public static void Main(String[] args)
{
var iterations = 5000;
m_out = new char[iterations * 2];
var task1 = Task.Run(()=>DemoTask(iterations, '+'));
var task2 = Task.Run(()=>DemoTask(iterations, '-'));
var res1 = task1.Result;
var res2 = task2.Result;
for (int i = 0; i < m_out.Length; i++)
{
Console.Write(m_out[i]);
}
Console.WriteLine("\nResults:");
Console.WriteLine(res1);
Console.WriteLine(res2);
}
private static String DemoTask(int iterations, char label)
{
for (int i = 0; i < iterations; i++)
{
int index = Interlocked.Increment(ref m_index);
m_out[index] = label;
}
return label + " result";
}
}
Run Code Online (Sandbox Code Playgroud)