如何在循环多线程任务的JSON序列化过程中避免集合修改?

时间:2019-05-09 10:16:44

标签: c# task jsonserializer

使用Newtonsoft.Json时,在序列化为JSON文件时遇到问题。

在循环中,我在各个线程中执行任务:

List<Task> jockeysTasks = new List<Task>();

            for (int i = 1; i < 1100; i++)
            {
                int j = i;
                Task task = Task.Run(async () =>
                {
                    LoadedJockey jockey = new LoadedJockey();
                    jockey = await Task.Run(() => _scrapServices.ScrapSingleJockeyPL(j));

                    if (jockey.Name != null)
                    {
                        _allJockeys.Add(jockey);
                    }

                    UpdateStatusBar = j * 100 / 1100;

                    if (j % 100 == 0)
                    {
                        await Task.Run(() => _dataServices.SaveAllJockeys(_allJockeys)); //saves everything to JSON file
                    }
                });

                jockeysTasks.Add(task);
            }

            await Task.WhenAll(jockeysTasks);

还有if (j % 100 == 0),正在努力将集合_allJockeys保存到文件中(我将做一些计数,使其更可靠,但这不是重点):

public void SaveAllJockeys(List<LoadedJockey> allJockeys)
        {
            if (allJockeys.Count != 0)
            {
                if (File.Exists(_jockeysFileName)) File.Delete(_jockeysFileName);

                try
                {
                    using (StreamWriter file = File.CreateText(_jockeysFileName))
                    {
                        JsonSerializer serializer = new JsonSerializer();
                        serializer.Serialize(file, allJockeys);
                    }
                }
                catch (Exception e)
                {
                    dialog.ShowDialog("Could not save the results, " + e.ToString(), "Error");
                }
            }
        }

在那段时间里,正如我所相信的那样,另一个任务是向集合中添加新的集合项,这给我抛出了一个例外:

  

集合已修改;枚举操作可能无法执行。

正如我在THE ARTICLE中所阅读的那样,您可以更改迭代类型以避免出现异常。据我所知,我无法修改Newtonsoft.Json包的工作方式。

在此先感谢您提供任何避免异常的提示,以及如何在不进行意外更改的情况下保存集合。

2 个答案:

答案 0 :(得分:0)

您可能应该继承自List并使用ReaderWriterLock(https://docs.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlock?view=netframework-4.8

即(未经测试的伪C#)

public class MyJockeys: List<LoadedJockey>
{

    System.Threading.ReaderWriterLock _rw_lock = new System.Threading.ReaderWriterLock();

    public new Add(LoadedJockey j)
    {
       try
       {
           _rw_lock.AcquireWriterLock(5000); // or whatever you deem an acceptable timeout
          base.Add(j);
       }
       finally
       {
           _rw_lock.ReleaseWriterLock();
       }
    }

    public ToJSON()
    {
       try
       {
           _rw_lock.AcquireReaderLock(5000); // or whatever you deem an acceptable timeout
          string s = "";  // Serialize here using Newtonsoft
          return s;
       }
       finally
       {
           _rw_lock.ReleaseReaderLock();
       }
    }
    // And override Remove and anything else you need
}

有主意吗?

希望这会有所帮助。

此致

亚当。

答案 1 :(得分:0)

我想在集合上使用ToList(),这会创建列表的副本,并产生积极的影响。