C# 并行数据处理混淆了一些信息

C# 并行数据处理混淆了一些信息,c#,mysql,multithreading,concurrency,parallel-processing,C#,Mysql,Multithreading,Concurrency,Parallel Processing,我正在尝试开发一个具有并行数据处理和使用MySQL的应用程序。这是我遇到问题的一段代码 public ConcurrentDictionary<string, Info> GetDatabaseForCurrentDay(System.DateTime day) { string[] date = day.ToShortDateString().Split('.'); string sqlQuery = "SELECT * FROM t

我正在尝试开发一个具有并行数据处理和使用MySQL的应用程序。这是我遇到问题的一段代码

    public ConcurrentDictionary<string, Info> GetDatabaseForCurrentDay(System.DateTime day)
    {
        string[] date = day.ToShortDateString().Split('.');
        string sqlQuery = "SELECT * FROM testtable WHERE Date ='" + date[2] + "-" + date[1] + "-" + date[0] + "';";
        ConcurrentDictionary<string, Info> info = new ConcurrentDictionary<string, Info>();
        Info[] dayInfo = null;
        Parallel.ForEach(ReadData(ConnectionString, sqlQuery), data =>
        {
            int num = 2;
            string[] dataPieces = data.Split(new char[] { ',' }, num);
            FileHelpers.FileHelperEngine<Info> engine = new FileHelpers.FileHelperEngine<Info>();
            dayInfo = engine.ReadString(dataPieces[1], int.MaxValue);
            info.TryAdd(dataPieces[0], dayInfo[0]);
        });       
        return info;
    }

现在,让我们回到问题上来。代码可以编译并运行,但返回的结果不正确。我注意到,
ConcurrentDictionary
包含具有错误值的键——简言之,
info.TryAdd(dataPieces[0],dayInfo[0])
可能会插入一个线程的键和另一个线程的值,因此,数据可能会损坏。我知道这种行为是并行处理的挫折,但不能忽略这种方法。我尝试了不同的方法来解决这个问题,但是没有任何效果,数据仍然是错误的。这个问题有什么解决方案可以保持代码的执行速度并保存数据吗?

您需要将
dayInfo
移动到并行for循环中。基本上,这是一个共享变量,每个任务都会不断写入它,从而产生垃圾结果。如果您将其放入委托中,那么对于每个迭代,它将是一个不同的私有变量,并且不会被破坏:

// Info[] dayInfo = null;   <--Remove this
Parallel.ForEach(ReadData(ConnectionString, sqlQuery), data =>
{
    int num = 2;
    string[] dataPieces = data.Split(new char[] { ',' }, num);
    FileHelpers.FileHelperEngine<Info> engine = new FileHelpers.FileHelperEngine<Info>();

    //declare dayInfo locally within this scope instead 
    var dayInfo = engine.ReadString(dataPieces[1], int.MaxValue);
    info.TryAdd(dataPieces[0], dayInfo[0]);
});       
//Info[]dayInfo=null;
{
int num=2;
string[]dataPieces=data.Split(新字符[]{',},num);
FileHelpers.FileHelperEngine=新建FileHelpers.FileHelperEngine();
//改为在此范围内本地声明dayInfo
var dayInfo=engine.ReadString(数据块[1],int.MaxValue);
info.TryAdd(数据块[0],dayInfo[0]);
});       

您需要将
dayInfo
移动到并行for循环中。基本上,这是一个共享变量,每个任务都会不断写入它,从而产生垃圾结果。如果您将其放入委托中,那么对于每个迭代,它将是一个不同的私有变量,并且不会被破坏:

// Info[] dayInfo = null;   <--Remove this
Parallel.ForEach(ReadData(ConnectionString, sqlQuery), data =>
{
    int num = 2;
    string[] dataPieces = data.Split(new char[] { ',' }, num);
    FileHelpers.FileHelperEngine<Info> engine = new FileHelpers.FileHelperEngine<Info>();

    //declare dayInfo locally within this scope instead 
    var dayInfo = engine.ReadString(dataPieces[1], int.MaxValue);
    info.TryAdd(dataPieces[0], dayInfo[0]);
});       
//Info[]dayInfo=null;
{
int num=2;
string[]dataPieces=data.Split(新字符[]{',},num);
FileHelpers.FileHelperEngine=新建FileHelpers.FileHelperEngine();
//改为在此范围内本地声明dayInfo
var dayInfo=engine.ReadString(数据块[1],int.MaxValue);
info.TryAdd(数据块[0],dayInfo[0]);
});       

只是澄清一下:如何准确地从循环范围中获取数据?如果我使用一个委托,它不是同一问题的另一个副本吗?我的意思是,你应该在现有委托中声明
dayInfo
,就像你对
dataPieces
所做的那样,以保持它在该范围的局部。用修改过的代码片段更新答案。另外,我想澄清的是,
dayInfo
的引用每次都会被一个新数组覆盖——而不是
Info[]
的同一个实例中的值。如我所述更改代码不会创建更多或更少的
Info[]
,而是将对新
Info[]
变量的引用保持为单独的。@Tim“Update answer with…”检测到Git commit消息!:我只是想澄清一下:如何从循环范围中准确地获取数据?如果我使用一个委托,它不是同一问题的另一个副本吗?我的意思是,你应该在现有委托中声明
dayInfo
,就像你对
dataPieces
所做的那样,以保持它在该范围的局部。用修改过的代码片段更新答案。另外,我想澄清的是,
dayInfo
的引用每次都会被一个新数组覆盖——而不是
Info[]
的同一个实例中的值。如我所述更改代码不会创建更多或更少的
Info[]
,而是将对新
Info[]
变量的引用保持为单独的。@Tim“Update answer with…”检测到Git commit消息!:P