我有一个处理Excel文件(以前已上传到服务器)的Web服务,该服务涉及大量数据库更新,并且需要花费相当长的时间。我想提供另一个Web服务,可以调用该服务来检查此过程的进度。它将进程的ID(可能是GUID)作为输入,并返回指示进度的int(0-100)。

我的想法是,长时间运行的服务可以创建仅内存的MemoryMappedFile(MMF)(仅需要sizeof(int)个字节),它会每隔一段时间报告其进度。然后,“进度”服务可以打开MMF,读取int,并向呼叫者报告。

我有两个问题。首先,我在MMF方面没有太多经验,所以这里有我可能没有意识到的陷阱吗?其次,更重要的一点是,鉴于只有一个编写器,在这种情况下是否需要同步?经过一番搜索,我无法发现MemoryMappedViewAccessor.Write对于int是否是原子的。

最佳答案

起初我不确定,因为我以前没有将MMF用于IPC,但是我现在使用the samples on MSDN进行了测试。

简短的回答是“否”,同步是没有必要的(如果您考虑一下,这很有意义)。作为控制台应用程序,您同时在两个示例下(编写器进程和读取器进程)。

唯一的问题是,您希望在每次读/写之后将写/读流中的光标位置重置为0,或者为前32位创建视图映射。不确定第二个是否可行(很可能没有,并且您仍然必须重置文件指针)。

编写过程:

    static void Main(string[] args)
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
        {
            int i = 0;
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    while (i++ < 10000)
                    {
                        writer.Write(i);
                        Thread.Sleep(50);
                        writer.Seek(0, SeekOrigin.Begin);
                    }
                }
            }

            Console.WriteLine("Done");
            Console.ReadLine();
        }
    }


读者流程:

    static void Main(string[] args)
    {
        try
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
            {
                using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                {
                    using (BinaryReader reader = new BinaryReader(stream))
                    {
                        int value = 0;
                        while (value != 10000)
                        {
                            value = reader.ReadInt32();
                            Console.WriteLine("Process A says: {0}", value);
                            stream.Seek(0L, SeekOrigin.Begin);
                            Thread.Sleep(20);
                        }
                    }
                }
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first.");
        }
    }


我故意使读取器在两次读取之间的等待时间少于写入器在两次写入之间的等待时间,以确保没有巧合。

输出是预期的,尽管没有等待它完成:

Process A says: 85
Process A says: 85
Process A says: 85
Process A says: 86
Process A says: 86
Process A says: 87
Process A says: 87
Process A says: 87
Process A says: 88
Process A says: 88
Process A says: 89
Process A says: 89
Process A says: 89
Process A says: 90
Process A says: 90
Process A says: 91
Process A says: 91
Process A says: 91
Process A says: 92
Process A says: 92
Process A says: 93
Process A says: 93
Process A says: 93
Process A says: 94


话虽如此,我仍然不推荐MMF。根据您的描述,您可以将进度静态地(可能在并发集合中)无问题地静态存储在报告进度的服务中。您可以通过仅公开另一个端点或方法来解决此问题,第二个服务可以调用该端点或方法来更新特定客户端/文件的进度。完成后,它只是告诉它从内存中删除它。

10-07 19:32