Zielony Smok - logo witryny

Macierze – mapowanie pliku na pamięć (Java)

Załóżmy, że musimy pomnożyć dwie macierze o wielkości 20000 × 20000, czyli zawierające po 400 000 000 elementów, umieszczone w plikach. Tak dużego pliku prawdopodobnie nie uda się w ogóle otworzyć, gdyż sterta Javy jest zbyt mała. Nie uda się go otworzyć w żadnym edytorze. Najlepszym rozwiązaniem jest wykorzystanie mapowania pliku na pamięć, czyli obiektu MappedByteBuffer. Jest to bufor bezpośredni, czyli umieszczony w pamięci operacyjnej poza stertą Javy, co daje olbrzymie możliwości, gdyż unika się używania buforów pośrednich oraz czasochłonnych operacji I/O. Mapowanie ma sens, gdy musimy utworzyć naprawdę duże pliki, długo utrzymywane w pamięci, na których wykonuje się dużo operacji, chociaż oczywiście możesz używać buforów bezpośrednich kiedy tylko chcesz. Bufory bezpośrednie nie będące MappedByteBuffer można używać niezależnie od plików.

Do pomnożenia dwu macierzy możemy użyć metody multiply4() z klasy MatrixUtil.

Obliczenia przeprowadzimy w klasie Matrix076:

Tworzymy dwie macierze z losowymi wartościami oraz trzecią macierz zerową do zapisywania wyników mnożenia. Następnie dla sprawdzenia wykonujemy mnożenie standardowe, a następnie właściwe mnożenie na zmapowanych plikach. Tutaj tworzymy macierze 8×8, ale metoda będzie działać dla dowolnych wielkości macierzy, o ile wielkość plików nie będzie przekraczać 4,17 GB. Jeśli przekracza można pomyśleć o partycjonowaniu, czyli o podziale macierzy wyjściowych na podmacierze i zapisaniu podmacierzy w (mniejszych) plikach. Wtedy jesteśmy ograniczeni wyłącznie wielkością pamięci stałej.

package matrices2;
import matrices.Matrix;
import matrices.MatrixUtil;
import matrices.Util;
import java.io.IOException;
public class Matrix076 {
    public static final int INT_SIZE = 4;
    public static final int DOUBLE_SIZE = 8;
    public static void main(String[] args) {
        int size = 8;
        Matrix matA = MatrixUtil.randomMatrix(size, -3, 5);
        matA.printToConsole();
        Util.print("");
        try {
            MatrixUtil.writeMatrix(matA, "matrices/assets/matrix076A.dat");
        } catch (IOException e) {
            e.printStackTrace();
        }
        Matrix matB = MatrixUtil.randomMatrix(size, 2, 8);
        matB.printToConsole();
        Util.print("");
        try {
            MatrixUtil.writeMatrix(matB, "matrices/assets/matrix076B.dat");
        } catch (IOException e) {
            e.printStackTrace();
        }
        Matrix matC = new Matrix(size, size);
        matC.setToValue(0.0);
        try {
            MatrixUtil.writeMatrix(matC, "matrices/assets/matrix076C.dat");
        } catch (IOException e) {
            e.printStackTrace();
        }
        matC.printToConsole();
        Util.print("");
        Matrix matD = MatrixUtil.multiply3(matA, matB);
        matD.printToConsole();
        Util.print("");
        MatrixUtil.multiply4("matrices/assets/matrix076A.dat", "matrices/assets/matrix076B.dat",
                "matrices/assets/matrix076C.dat");
        Matrix matE = MatrixUtil.readMatrix("matrices/assets/matrix076C.dat");
        matE.printToConsole();
        Util.print("");
    }
}

Po uruchomieniu kodu na konsoli zobaczymy:

Macierz A
3.0 3.0 -1.0 -1.0 -3.0 0.0 -3.0 -3.0
-3.0 3.0 5.0 3.0 2.0 1.0 -2.0 -2.0
4.0 -1.0 4.0 0.0 -1.0 2.0 2.0 -2.0
3.0 4.0 4.0 -3.0 5.0 -1.0 0.0 -3.0
4.0 -1.0 3.0 3.0 -2.0 -1.0 5.0 5.0
2.0 1.0 0.0 5.0 0.0 -2.0 4.0 -3.0
-2.0 -3.0 -2.0 2.0 2.0 5.0 3.0 1.0
0.0 -3.0 5.0 1.0 3.0 3.0 3.0 3.0
Macierz B
2.0 7.0 8.0 6.0 2.0 7.0 6.0 7.0
3.0 6.0 6.0 7.0 3.0 3.0 6.0 5.0
6.0 3.0 5.0 5.0 6.0 6.0 2.0 4.0
4.0 3.0 3.0 6.0 7.0 3.0 8.0 2.0
5.0 7.0 4.0 7.0 2.0 8.0 8.0 8.0
2.0 5.0 6.0 4.0 6.0 8.0 5.0 5.0
6.0 3.0 5.0 5.0 3.0 7.0 3.0 5.0
2.0 8.0 5.0 8.0 2.0 2.0 2.0 2.0
Macierz C
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Macierz powstała w wyniku standardowego mnożenia
-34.0 -21.0 -8.0 -32.0 -19.0 -30.0 -13.0 -15.0
41.0 18.0 22.0 38.0 54.0 33.0 45.0 27.0
36.0 27.0 54.0 32.0 41.0 67.0 30.0 47.0
47.0 54.0 58.0 55.0 19.0 74.0 55.0 80.0
63.0 76.0 86.0 97.0 59.0 73.0 52.0 55.0
41.0 13.0 30.0 37.0 36.0 38.0 54.0 33.0
23.0 24.0 20.0 26.0 34.0 50.0 34.0 25.0
70.0 69.0 70.0 82.0 67.0 99.0 54.0 67.0
Macierz powstała w wyniku mnożenia z mapowaniem plików na pamięć
-34.0 -21.0 -8.0 -32.0 -19.0 -30.0 -13.0 -15.0
41.0 18.0 22.0 38.0 54.0 33.0 45.0 27.0
36.0 27.0 54.0 32.0 41.0 67.0 30.0 47.0
47.0 54.0 58.0 55.0 19.0 74.0 55.0 80.0
63.0 76.0 86.0 97.0 59.0 73.0 52.0 55.0
41.0 13.0 30.0 37.0 36.0 38.0 54.0 33.0
23.0 24.0 20.0 26.0 34.0 50.0 34.0 25.0
70.0 69.0 70.0 82.0 67.0 99.0 54.0 67.0

Pliki do ściągnięcia

matrices027.zip

Moduł matrices – aktualny stan projektu = 027;