0

これが私のコードです:

using System;

using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;

using System.Threading;
using System.Threading.Tasks;

using System.IO;
using System.IO.MemoryMappedFiles;

namespace CopyFile
{
class Program
{
    static void Main()
    {
        long length = 0;
        byte[] buffer;
        string source_path, dest_path;
        source_path = Console.ReadLine();
        dest_path = Console.ReadLine();
        FileInfo fi = new FileInfo(source_path);
        length = (int)fi.Length;
        // Create disk file
        using (FileStream fs = File.Create(dest_path))
        {
            fs.Close();
        }
        // Create unnamed MMF
        var mmf1 = MemoryMappedFile.CreateFromFile(source_path, FileMode.OpenOrCreate, null, length);
        // Create reader to MMF
        var reader = mmf1.CreateViewAccessor(0, length, MemoryMappedFileAccess.Read);
        // Create unnamed MMF
        var mmf2 = MemoryMappedFile.CreateFromFile(dest_path, FileMode.Create, null, length);
        // Create writer to MMF
        var writer = mmf2.CreateViewAccessor(0, length, MemoryMappedFileAccess.Write);

        int read_block = int.Parse(Math.Min(length, 512 * 1024).ToString());//4k
        int end_read_block = int.Parse(length.ToString()) % read_block;

        int[] offset_array = new int[int.Parse((length - read_block).ToString()) / read_block];
        for (int offset = 0,i=0; i < int.Parse((length - read_block).ToString()) / read_block; i++,offset += read_block)
        {
            offset_array[i] = offset;
        }

        /*
        Parallel.ForEach<int>(offset_array, offset =>
        {
            // Read from MMF
            buffer = new byte[read_block];
            reader.ReadArray<byte>(offset, buffer, 0, read_block);
            // Write to MMF
            writer.WriteArray<byte>(offset, buffer, 0, read_block);
        });
         */
        foreach (int offset in offset_array)
        {
            // Read from MMF
            buffer = new byte[read_block];
            reader.ReadArray<byte>(offset, buffer, 0, read_block);
            // Write to MMF
            writer.WriteArray<byte>(offset, buffer, 0, read_block);
        }

        buffer = new byte[end_read_block];
        reader.ReadArray<byte>(length - end_read_block, buffer, 0, end_read_block);
        // Write to MMF
        writer.WriteArray<byte>(length - end_read_block, buffer, 0, end_read_block);

    }
}
}

1つのファイルをコピーして、それが機能している別の場所に貼り付けようとします

しかし、Parallel.foreachまたはParallel.forを使用しようとすると、1つのファイルをコピーするときに、コピーされたファイルがソースファイルと異なります。

(Parallel.foreachセクションにコメントしました)

理由がわからない

ありがとう

4

2 に答える 2

2

あなたのコードでは;

Parallel.ForEach<int>(offset_array, offset =>
{
    // Read from MMF
    buffer = new byte[read_block];
    reader.ReadArray<byte>(offset, buffer, 0, read_block);
    // Write to MMF
    writer.WriteArray<byte>(offset, buffer, 0, read_block);
});

bufferは共有変数であるため、すべてのスレッドがそれを共有します。たとえば、スレッド1はバッファを割り当て、ファイルから読み取り、スレッド2はバッファを再割り当てしてファイルを読み取り、スレッド1はスレッド2のバッファの内容を書き込みます。

それをより良く機能させるために、バッファをループ内のローカル変数、a'la;にします。

Parallel.ForEach<int>(offset_array, offset =>
{
    // Read from MMF
    byte[] buffer = new byte[read_block];
    reader.ReadArray<byte>(offset, buffer, 0, read_block);
    // Write to MMF
    writer.WriteArray<byte>(offset, buffer, 0, read_block);
});

これにより、すべてのスレッドが独自のローカルバッファを持つことができます。

ドキュメントを見ると、物事は暗いように見えますが、インスタンスメソッド(ReadArray / WriteArray)はスレッドセーフであるとは限りません。つまり、バッファの問題を修正しても、動作する保証はありません。

于 2012-08-15T16:33:31.273 に答える
0

ファイルをコピーするためのあなたのアプローチは良くありません。Joachim Isakssonが説明した問題のほかに、問題は、複数のスレッドから同時にファイルストリームにアクセスしていることです。これは、1つのスレッドT1がデータを読み取り、次にスケジューラーが制御をスレッドT2に渡し、スレッドT2がデータを読み取り、それを宛先に書き込む可能性があることを意味します。制御がT1に戻り、読み取りデータを書き込むと、破損したファイルが発生します。CPUはこの操作のボトルネックではないため、同時実行を使用してファイルをコピーする理由はありません。より速い結果は得られず、CPUサイクルを浪費するだけです。

于 2012-08-15T16:42:31.637 に答える