Κοινή χρήση τεχνολογίας

Πλήρης παιδεία στο μοντέλο δικτύου Java

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

ΣΦΑΙΡΙΚΗ ΕΙΚΟΝΑ

Περιγράφει τις βασικές γνώσεις του NIO σε επίπεδο ava, για βασική αναθεώρηση

1. Επισκόπηση NIO

Στην Java, το NIO (Non-blocking I/O or New I/O) είναι ένα νέο σύνολο API λειτουργίας εισόδου/εξόδου που εισήχθη στην Java SE 1.4 και σε επόμενες εκδόσεις.

Σε σύγκριση με το παραδοσιακό μοντέλο IO, παρέχει υψηλότερη απόδοση και καλύτερες δυνατότητες ταυτόχρονης επεξεργασίας. Το βασικό χαρακτηριστικό του NIO είναι η δυνατότητα μη αποκλεισμού, η οποία επιτρέπει σε ένα νήμα να διαχειρίζεται πολλαπλά κανάλια I/O, βελτιώνοντας έτσι σημαντικά την απόδοση της εφαρμογής σε σενάρια υψηλού συγχρονισμού.

Το σενάριο χρήσης του Java NIO είναι ιδιαίτερα κατάλληλο για περιπτώσεις όπου απαιτείται επεξεργασία μεγάλου αριθμού ταυτόχρονων συνδέσεων, για παράδειγμα, σε έναν διακομιστή δικτύου, ένα νήμα μπορεί να διαχειριστεί χιλιάδες συνδέσεις πελάτη χωρίς να χρειάζεται να εκχωρηθεί ένα ανεξάρτητο νήμα για κάθε σύνδεση. Μπορεί να μειώσει σημαντικά την κατανάλωση πόρων του συστήματος και να βελτιώσει τις δυνατότητες επεξεργασίας

2. Τρία κύρια στοιχεία του NIO στην Java

1. Κανάλια

Το κανάλι είναι το μέσο ροής δεδομένων στο Java NIO Είναι αμφίδρομο και μπορεί να χρησιμοποιηθεί για την ανάγνωση δεδομένων ή την εγγραφή δεδομένων. Το κύριο πλεονέκτημα των καναλιών είναι ότι δεν αποκλείονται, πράγμα που σημαίνει ότι ένα νήμα μπορεί να διαχειριστεί πολλά κανάλια Όταν δεν συμβαίνουν συμβάντα σε ένα κανάλι, το νήμα δεν θα αποκλειστεί και μπορεί να χειριστεί άλλες εργασίες. Οι κύριοι τύποι καναλιών περιλαμβάνουν:

  • FileChannel: Χρησιμοποιείται για λειτουργίες ανάγνωσης και εγγραφής αρχείων. Μπορεί να χρησιμοποιηθεί για την εγγραφή δεδομένων από το buffer στο αρχείο ή για την ανάγνωση δεδομένων από το αρχείο στο buffer.
  • SocketChannel: Χρησιμοποιείται για συνδέσεις TCP σε επικοινωνίες δικτύου και μπορεί να χρησιμοποιηθεί για ανάγνωση και εγγραφή δεδομένων.
  • ServerSocketChannel: Χρησιμοποιείται για την αποδοχή νέων συνδέσεων SocketChannel, παρόμοια με το παραδοσιακό ServerSocket.
  • DatagramChannel: Χρησιμοποιείται για επικοινωνία UDP, η οποία μπορεί να στείλει και να λάβει datagrams.

2. Buffers

Το buffer είναι ένα αντικείμενο που χρησιμοποιείται για την αποθήκευση δεδομένων στο NIO Είναι ένας πίνακας byte που μπορεί να γράψει δεδομένα και να διαβάσει δεδομένα από αυτό. Ένα buffer έχει μια συγκεκριμένη χωρητικότητα και έχει δύο σημαντικές ιδιότητες: θέση και όριο.

  • Χωρητικότητα: Ο μέγιστος αριθμός στοιχείων που μπορεί να αποθηκεύσει η προσωρινή μνήμη.
  • Θέση: Το ευρετήριο του στοιχείου στο οποίο λειτουργεί αυτή τη στιγμή, το οποίο αλλάζει κατά την ανάγνωση ή την εγγραφή των δεδομένων.
  • Οριο: Στη λειτουργία ανάγνωσης, η μέγιστη τιμή που μπορεί να φτάσει η θέση στη λειτουργία εγγραφής, η θέση δεν μπορεί να υπερβαίνει την τιμή.

Οι κύριοι τύποι buffer είναιByteBufferCharBufferShortBufferIntBufferLongBufferFloatBufferκαιDoubleBuffer, κάθε τύπος αντιστοιχεί σε έναν πρωτόγονο τύπο δεδομένων.

3. Επιλογείς

Ένας επιλογέας είναι ένας πολυπλέκτης στο NIO που επιτρέπει σε ένα νήμα να παρακολουθεί συμβάντα από πολλά κανάλια, όπως ανάγνωση, εγγραφή, σύνδεση και λήψη συμβάντων. Ο επιλογέας ειδοποιεί την εφαρμογή όταν ένα από τα κανάλια είναι έτοιμο για λειτουργίες I/O. Η χρήση επιλογέων βελτιώνει σημαντικά τις δυνατότητες επεξεργασίας ταυτόχρονης χρήσης των εφαρμογών δικτύου επειδή δεν χρειάζεται να δημιουργηθεί ένα νήμα για κάθε σύνδεση.

Οι κύριες μέθοδοι επιλογής περιλαμβάνουν:

  • select(): Αποκλείεται έως ότου τουλάχιστον ένα κανάλι είναι έτοιμο για λειτουργίες I/O.
  • selectedKeys(): Επιστρέφει ένα σύνολο που περιέχει τα αντικείμενα SelectionKey όλων των προετοιμασμένων καναλιών.
  • wakeup(): Η διακοπή μπλοκαρίστηκεselect()ΜΕΤΑΦΟΡΑ.

SelectionKeyΕίναι η συσχέτιση μεταξύ επιλογέων και καναλιών Αντιπροσωπεύει την κατάσταση εγγραφής ενός καναλιού στον επιλογέα, συμπεριλαμβανομένων των καναλιών, των επιλογέων, των συλλογών ενδιαφερομένων συμβάντων και των έτοιμων συλλογών συμβάντων.

3. Προγραμματισμός δικτύου

1. Αποκλεισμός I/O

Αυτό είναι το πιο παραδοσιακό μοντέλο I/O Στην Java, τα παραδοσιακά API Socket και ServerSocket βασίζονται στον αποκλεισμό I/O. Σε αυτήν τη λειτουργία, όταν ένα νήμα ξεκινά μια λειτουργία ανάγνωσης ή εγγραφής, το νήμα μπλοκάρεται μέχρι να ολοκληρωθεί η λειτουργία I/O. Εάν δεν υπάρχουν δεδομένα προς ανάγνωση για τη λειτουργία ανάγνωσης ή η λειτουργία εγγραφής δεν μπορεί να ολοκληρωθεί αμέσως, το νήμα θα περιμένει μέχρι να ολοκληρωθεί η λειτουργία.

Χαρακτηριστικά:

  • Απλό μοντέλο προγραμματισμού: Εύκολη κατανόηση και εφαρμογή.
  • Απασχόληση πόρων: Κάθε σύνδεση απαιτεί ένα ανεξάρτητο νήμα, με αποτέλεσμα περιορισμένο αριθμό νημάτων και υψηλή κατανάλωση πόρων.
  • Περιορισμοί απόδοσης: Σε σενάρια υψηλής συγχρονισμού, η εναλλαγή νημάτων και η εναλλαγή περιβάλλοντος είναι δαπανηρές και μπορούν εύκολα να γίνουν σημεία συμφόρησης.

2. I/O χωρίς αποκλεισμό

​ Το μη αποκλειστικό I/O είναι μέρος του πλαισίου Java NIO (New I/O), το οποίο επιτρέπει στα νήματα να ξεκινούν λειτουργίες ανάγνωσης και εγγραφής χωρίς αποκλεισμό. Εάν δεν υπάρχουν δεδομένα προς ανάγνωση για μια λειτουργία ανάγνωσης ή η λειτουργία εγγραφής δεν μπορεί να ολοκληρωθεί αμέσως, το νήμα δεν θα τεθεί σε αναστολή και μπορεί να συνεχίσει να εκτελεί άλλες εργασίες.

Χαρακτηριστικά:

  • ευκαμψία: Τα νήματα μπορούν να χειριστούν περισσότερες συνδέσεις επειδή δεν είναι μπλοκαρισμένα σε αναμονή για λειτουργίες I/O.
  • Αυξημένη πολυπλοκότητα: Ο προγραμματιστής πρέπει να ελέγξει ρητά εάν η λειτουργία έχει ολοκληρωθεί, γεγονός που αυξάνει τη δυσκολία του προγραμματισμού.
  • Βελτιώσεις απόδοσης: Σε σενάρια υψηλής συγχρονισμού, η επιβάρυνση που προκαλείται από την εναλλαγή νημάτων μπορεί να μειωθεί σημαντικά.

3. Πολυπλεξία

Η πολυπλεξία είναι η παρακολούθηση πολλών περιγραφέων αρχείων ταυτόχρονα μέσω ενός νήματος και λειτουργεί μόνο σε έναν περιγραφέα όταν είναι έτοιμος (συνήθως σημαίνει ότι τα δεδομένα είναι αναγνώσιμα ή η προσωρινή μνήμη εγγραφής είναι εγγράψιμο). Οι επιλογείς χρησιμοποιούνται στην Java για την υλοποίηση της πολυπλεξίας.

Χαρακτηριστικά:

  • Υψηλή ταυτόχρονη: Ένα νήμα μπορεί να χειριστεί χιλιάδες συνδέσεις, βελτιώνοντας σημαντικά την απόδοση του διακομιστή.
  • Αποτελεσματικός: Μόνο όταν μια λειτουργία I/O είναι έτοιμη, το νήμα θα αφυπνιστεί για να αποφευχθεί η περιττή εναλλαγή νήματος.
  • Εξοικονόμηση πόρων: Σε σύγκριση με τον αποκλεισμό I/O, οι διακομιστές στο μοντέλο πολυπλεξίας μπορούν να χρησιμοποιήσουν τους πόρους του συστήματος πιο αποτελεσματικά.

Ειδοποίηση:

Σε πρακτικές εφαρμογές, η μη αποκλειστική I/O χρησιμοποιείται συχνά σε συνδυασμό με την πολυπλεξία. Για παράδειγμα, ένας διακομιστής μπορεί να χρησιμοποιήσει έναν Επιλογέα για την παρακολούθηση πολλών SocketChannel Όταν ένα SocketChannel έχει δεδομένα που μπορούν να διαβαστούν ή να γραφτούν, ο Επιλογέας θα ειδοποιήσει τον διακομιστή και ο διακομιστής θα επεξεργαστεί αυτό το συγκεκριμένο SocketChannel με μη αποκλειστικό τρόπο.

4.NIO VS BIO

4.1 Ροή έναντι καναλιού

Στην Java, το Stream και το Channel είναι δύο διαφορετικοί τρόποι επεξεργασίας ροών δεδομένων. Ανήκουν στην τυπική βιβλιοθήκη IO της Java και στη βιβλιοθήκη NIO αντίστοιχα. Ακολουθεί μια λεπτομερής σύγκριση των δύο εννοιών:

Ρεύμα

Το Stream είναι μέρος του τυπικού μοντέλου IO (blocking IO) της Java, το οποίο παρέχει έναν τρόπο διαδοχικής ανάγνωσης και εγγραφής δεδομένων. Το Stream χωρίζεται σε δύο τύπους: InputStream και OutputStream, που χρησιμοποιούνται για την ανάγνωση και εγγραφή δεδομένων αντίστοιχα.Αυτές οι ροές μπορεί να είναι ροές byte (όπως πInputStream, OutputStream) ή μια ροή χαρακτήρων (όπωςReader, Writer)。

Χαρακτηριστικά:

  • Κωλυσιεργικός: Από προεπιλογή, οι λειτουργίες ροής μπλοκάρουν, δηλαδή, εάν δεν υπάρχουν δεδομένα για ανάγνωση στη λειτουργία ανάγνωσης ή η λειτουργία εγγραφής δεν μπορεί να ολοκληρωθεί αμέσως, το νήμα κλήσης θα αποκλειστεί μέχρι να ολοκληρωθεί η λειτουργία.
  • Μονοκατευθυντικότητα: Κάθε ροή έχει μια κατεύθυνση, είτε μόνο για ανάγνωση είτε μόνο για εγγραφή.
  • αυτόματη απενεργοποίηση: Αφού χρησιμοποιήσετε το Stream, συνήθως πρέπει να το καλέσετεclose() μέθοδος απελευθέρωσης πόρων.Ξεκινώντας από την Java 7, η δήλωση try-with-resources μπορεί να κλείσει αυτόματα την υλοποίησηAutoCloseableΠόροι διεπαφής, συμπεριλαμβανομένης της ροής.

Κανάλι

Το κανάλι είναι μέρος του μοντέλου Java NIO (New IO), το οποίο παρέχει υψηλότερο επίπεδο αφαίρεσης από το Stream, επιτρέποντας πιο αποτελεσματική επεξεργασία δεδομένων. Τα κανάλια μπορεί να είναι αμφίδρομα, που σημαίνει ότι μπορούν να χρησιμοποιηθούν για ανάγνωση και εγγραφή δεδομένων.Οι κύριοι τύποι καναλιών περιλαμβάνουνFileChannelSocketChannelServerSocketChannelκαιDatagramChannel

Χαρακτηριστικά:

  • μη μπλοκάρισμα :Το κανάλι μπορεί να διαμορφωθεί σε λειτουργία αποκλεισμού ή μη αποκλεισμού. Στη λειτουργία μη αποκλεισμού, εάν μια λειτουργία ανάγνωσης δεν έχει δεδομένα προς ανάγνωση ή μια λειτουργία εγγραφής δεν μπορεί να ολοκληρωθεί αμέσως, η λειτουργία θα επιστρέψει αμέσως αντί να μπλοκάρει το νήμα.
  • Λειτουργίες buffer:Οι λειτουργίες του καναλιού εκτελούνται πάντα μέσω του buffer (Η προσωρινή μνήμη διαβάζεται από το κανάλι στο buffer ή εγγράφεται από την προσωρινή μνήμη στο κανάλι).
  • Πολυπλεξία: Το κανάλι μπορεί να χρησιμοποιηθεί μαζί με το Selector για την επίτευξη πολυπλεξίας, επιτρέποντας σε ένα νήμα να παρακολουθεί τις λειτουργίες I/O πολλαπλών καναλιών και να βελτιώνει τις δυνατότητες ταυτόχρονης επεξεργασίας.

Συνοψίζω

  • Εφαρμόσιμη σκηνή: Το Stream είναι πιο κατάλληλο για επεξεργασία μικρότερων συνόλων δεδομένων ή απλών λειτουργιών αρχείων, ενώ το Channel είναι πιο κατάλληλο για επεξεργασία μεγάλων ποσοτήτων δεδομένων, ειδικά επικοινωνία δικτύου και λειτουργίες μεγάλων αρχείων, επειδή παρέχει υψηλότερη απόδοση και καλύτερες δυνατότητες ταυτόχρονης χρήσης .
  • Πολυπλοκότητα προγραμματισμού: Το API του Stream είναι σχετικά απλό και εύκολο στη χρήση, ενώ το API του Channel και το NIO είναι πιο περίπλοκα, αλλά παρέχουν πιο ισχυρές λειτουργίες και υψηλότερη απόδοση.
  • Διαχείριση πόρων: Είτε πρόκειται για ροή είτε για κανάλι, οι πόροι θα πρέπει να τυγχάνουν κατάλληλης διαχείρισης και να διασφαλίζεται ότι κλείνουν όταν δεν χρειάζονται πλέον για να αποφευχθούν διαρροές πόρων.

4.2 Μοντέλο IO

Στην Java, τα μοντέλα λειτουργίας I/O μπορούν να ταξινομηθούν με βάση τις δύο διαστάσεις σύγχρονη/ασύγχρονη και αποκλειστική/μη αποκλειστική.

4.2.1 Σύγχρονος αποκλεισμός I/O

ορισμός : Ο σύγχρονος αποκλεισμός I/O είναι το πιο παραδοσιακό μοντέλο I/O Όταν ένα νήμα καλεί μια λειτουργία I/O (όπως ανάγνωση ή εγγραφή), το νήμα θα αποκλειστεί μέχρι να ολοκληρωθεί η λειτουργία. Αυτό σημαίνει ότι το νήμα δεν μπορεί να εκτελέσει άλλες εργασίες μέχρι να ολοκληρωθεί η λειτουργία.

Χαρακτηριστικά

  • Απλό και εύκολο στη χρήση, η λογική του κώδικα είναι ξεκάθαρη.
  • Κάθε λειτουργία I/O απαιτεί ένα αποκλειστικό νήμα, το οποίο δεν είναι κατάλληλο για σενάρια υψηλού συγχρονισμού και μπορεί να οδηγήσει σε εξάντληση των πόρων του νήματος.
  • Χρησιμοποιείται συνήθως σεInputStreamOutputStreamSocketκαιServerSocketσκηνή.

Παράδειγμα:

Χρησιμοποιήστε το παραδοσιακόInputStreamκαιOutputStreamΓια να διαβάσετε και να γράψετε αρχεία:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class SyncBlockingIOExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("input.txt");
             FileOutputStream fos = new FileOutputStream("output.txt")) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

4.2.2 Σύγχρονη I/O χωρίς αποκλεισμό

ορισμός : Σε σύγχρονες I/O χωρίς αποκλεισμό, το νήμα δεν θα αποκλειστεί μετά την κλήση της λειτουργίας I/O. Εάν η λειτουργία δεν μπορεί να ολοκληρωθεί αμέσως, η μέθοδος θα επιστρέψει αμέσως, συνήθως επιστρέφοντας μια ειδική τιμή (όπως -1 ή 0) ή ρίχνοντας μια εξαίρεση για να υποδείξει ότι η λειτουργία δεν έχει ολοκληρωθεί.

Χαρακτηριστικά

  • Η κατάσταση λειτουργίας πρέπει να μετρηθεί μέχρι να ολοκληρωθεί η λειτουργία.
  • Υψηλότερη χρήση νημάτων επειδή τα νήματα μπορούν να εκτελούν άλλες εργασίες ενώ περιμένουν για I/O.
  • Η υλοποίηση είναι πιο περίπλοκη και πρέπει να χειρίζεται δημοσκοπήσεις και ελέγχους κατάστασης.
  • Βασισμένο σε Java NIOChannelsκαιBuffers, καλώνταςconfigureBlocking(false)Ρυθμίστε το κανάλι σε λειτουργία μη αποκλεισμού.

Παράδειγμα:

Χρησιμοποιώντας το NIOFileChannelΓια μη αποκλεισμό ανάγνωσης και γραφής:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;

public class SyncNonBlockingIOExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("input.txt");
             FileOutputStream fos = new FileOutputStream("output.txt");
             FileChannel inChannel = fis.getChannel();
             FileChannel outChannel = fos.getChannel()) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            inChannel.configureBlocking(false);
            while (inChannel.read(buffer) > 0) {
                buffer.flip();
                outChannel.write(buffer);
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

4.2.3 Σύγχρονη πολυπλεξία I/O

ορισμός: Χρήση μοντέλου σύγχρονης πολυπλεξίας I/OSelector(επιλογέας) για παρακολούθηση πολλαπλώνChannel Εκδήλωση.Όταν καλεί το νήμαSelector.select(), θα μπλοκάρει μέχρι να υπάρξει τουλάχιστον έναChannelΠροκύπτουν συμβάντα (όπως αναγνώσιμο, εγγράψιμο, αίτημα σύνδεσης κ.λπ.).

Χαρακτηριστικά

  • Επιτρέπει σε ένα νήμα να διαχειρίζεται πολλάChannel, βελτιώνει τη συγχρονικότητα.
  • πέρασμαSelectorκαιSelectionKeyΜηχανισμός που μπορεί να χειριστεί αποτελεσματικά μεγάλο αριθμό ταυτόχρονων συνδέσεων.
  • Κατάλληλο για σενάρια διακομιστή δικτύου, όπως διακομιστές web και διακομιστές συνομιλίας.
  • Βασισμένο στο πλαίσιο Java NIO.

Παράδειγμα:

Χρησιμοποιώντας το NIOFileChannelΓια μη αποκλεισμό ανάγνωσης και γραφής:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;

public class SyncMultiplexingIOExample {
    public static void main(String[] args) throws IOException {
        try (Selector selector = Selector.open();
             ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            serverSocketChannel.socket().bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                if (selector.select() > 0) {
                    Set<SelectionKey> keys = selector.selectedKeys();
                    for (SelectionKey key : keys) {
                        if (key.isAcceptable()) {
                            ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                            SocketChannel clientChannel = ssc.accept();
                            clientChannel.configureBlocking(false);
                            clientChannel.register(selector, SelectionKey.OP_READ);
                        }
                    }
                    keys.clear();
                }
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

4.2.4 Ασύγχρονη μη αποκλειστική I/O

ορισμός : Στο ασύγχρονο μοντέλο I/O χωρίς αποκλεισμό, το νήμα επιστρέφει αμέσως μετά την έναρξη της λειτουργίας I/O χωρίς να περιμένει να ολοκληρωθεί η λειτουργία. Όταν ολοκληρωθεί η λειτουργία, το νήμα θα ειδοποιηθεί ασύγχρονα μέσω μιας λειτουργίας επανάκλησης ή μιας ειδοποίησης συμβάντος.

Χαρακτηριστικά

  • Το πιο αποτελεσματικό μοντέλο εισόδου/εξόδου, τα νήματα δεν μπλοκάρονται καθόλου και μπορούν να εκτελέσουν άλλες εργασίες αμέσως.
  • πέρασμαAsynchronousChannelΗ διεπαφή και η υλοποίηση της υποκατηγορίας της, όπως π.χAsynchronousFileChannelκαιAsynchronousSocketChannel
  • Κατάλληλο για σενάρια υψηλής συγχρονισμού και υψηλής απόδοσης, όπως η επεξεργασία μεγάλων δεδομένων και οι διακομιστές δικτύου υψηλού φορτίου.
  • Η Java 7 εισήγαγε το ασύγχρονο μοντέλο I/O χωρίς αποκλεισμό.

Παράδειγμα:

Χρησιμοποιώντας το NIOAsynchronousFileChannelΕκτελέστε ασύγχρονη ανάγνωση και εγγραφή αρχείων:

import java.io.IOException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;

public class AsyncNonBlockingIOExample {
    public static void main(String[] args) throws IOException, InterruptedException {
        AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(Paths.get("input.txt"), StandardOpenOption.READ);
        AsynchronousFileChannel outChannel = AsynchronousFileChannel.open(Paths.get("output.txt"), StandardOpenOption.WRITE);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        CountDownLatch latch = new CountDownLatch(1);
        inChannel.read(buffer, 0, buffer, 0, (channel, result) -> {
            buffer.flip();
            outChannel.write(buffer, 0, buffer, 0, null);
            latch.countDown();
        });
        latch.await();
        inChannel.close();
        outChannel.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Σημείωση: Το ασύγχρονο μοντέλο απαιτεί υποστήριξη από το υποκείμενο λειτουργικό σύστημα (Kernel)

  • Τα συστήματα Windows υλοποιούν αληθινή ασύγχρονη IO μέσω IOCP
  • Το ασύγχρονο IO στο σύστημα Linux εισήχθη στην έκδοση 2.6, αλλά η υποκείμενη εφαρμογή του εξακολουθεί να χρησιμοποιεί πολυπλεξία για την προσομοίωση του ασύγχρονου IO και δεν υπάρχει πλεονέκτημα απόδοσης.

4.2.5 Ασύγχρονος αποκλεισμός I/O

ορισμός : Θεωρητικά, αυτό το μοντέλο δεν υπάρχει, γιατί "ασύγχρονο" σημαίνει ότι η λειτουργία εκτελείται στο παρασκήνιο και το νήμα δεν είναι μπλοκαρισμένο. Επομένως, ο ασύγχρονος αποκλεισμός εισόδου/εξόδου είναι μια αντιφατική έννοια και δεν θα εμφανιστεί στην πράξη.

4.2.6 Περίληψη

Η επιλογή του κατάλληλου μοντέλου εισόδου/εξόδου είναι κρίσιμη για τη διαχείριση απόδοσης και πόρων. Σε σενάρια υψηλής συγχρονισμού, τα μοντέλα σύγχρονων I/O χωρίς αποκλεισμό ή σύγχρονης πολυπλεξίας I/O είναι κοινές επιλογές Σε σενάρια που απαιτούν εξαιρετική απόδοση και ταχύτητα απόκρισης, το μοντέλο ασύγχρονης I/O χωρίς αποκλεισμό είναι η πρώτη επιλογή.

4.3 Μηδενικό αντίγραφο

Έννοια μηδενικού αντιγράφου

​Η τεχνολογία μηδενικού αντιγράφου σημαίνει ότι κατά τη διαδικασία μετάδοσης δεδομένων από το ένα μέρος στο άλλο, τα δεδομένα δεν χρειάζεται να αντιγραφούν μεταξύ του χώρου χρήστη και του χώρου πυρήνα, ή τουλάχιστον μειώνει τον αριθμό τέτοιων αντιγράφων, βελτιώνοντας έτσι την απόδοση του συστήματος. Στις παραδοσιακές λειτουργίες I/O, όταν τα δεδομένα διαβάζονται από το δίκτυο ή τον δίσκο, πρώτα αντιγράφονται στην προσωρινή μνήμη στο χώρο του πυρήνα και στη συνέχεια αντιγράφονται από το χώρο του πυρήνα στην προσωρινή μνήμη στο χώρο χρήστη. Αντίθετα, σε μηδενικό αντίγραφο, τα δεδομένα μπορούν να υποβληθούν σε επεξεργασία απευθείας στον χώρο του πυρήνα ή να μεταφερθούν απευθείας από τον χώρο του πυρήνα στη συσκευή δικτύου, μειώνοντας έτσι τη λειτουργία αντιγραφής της CPU, μειώνοντας την επιβάρυνση του συστήματος και βελτιώνοντας την αποτελεσματικότητα της μετάδοσης δεδομένων.

Πηγή μηδενικού αντιγράφου

Η έννοια του μηδενικού αντιγράφου εμφανίστηκε για πρώτη φορά στο σχεδιασμό του λειτουργικού συστήματος, με στόχο να λύσει το στενό σημείο απόδοσης που προκαλείται από την αντιγραφή δεδομένων σε παραδοσιακές λειτουργίες I/O. Στα πρώιμα συστήματα υπολογιστών, όλες οι λειτουργίες εισόδου/εξόδου απαιτούσαν πολλαπλά αντίγραφα δεδομένων στο χώρο του χρήστη και στον πυρήνα.

Βασικά τεχνικά σημεία

  • Απευθείας I/O: Επιτρέπει στις εφαρμογές την απευθείας πρόσβαση σε συσκευές δίσκου, παρακάμπτοντας τον μηχανισμό προσωρινής αποθήκευσης του συστήματος αρχείων.
  • Χαρτογράφηση μνήμης (MMAP): Αντιστοιχίστε τα αρχεία στη μνήμη έτσι ώστε να είναι δυνατή η πρόσβαση στα δεδομένα αρχείων όπως η μνήμη, μειώνοντας την αντιγραφή.
  • Αποστολή αρχείου: Κλήση συστήματος Linux που μπορεί να μεταφέρει δεδομένα απευθείας από ένα περιγραφικό αρχείου σε άλλο, αποφεύγοντας τα ενδιάμεσα αντίγραφα.
  • DMA (Άμεση πρόσβαση στη μνήμη): Τεχνολογία σε επίπεδο υλικού που επιτρέπει τη μεταφορά δεδομένων απευθείας μεταξύ της συσκευής και της μνήμης χωρίς τη συμμετοχή της CPU.

Υλοποίηση σε Java:

Η Java υποστηρίζει τεχνολογία μηδενικής αντιγραφής μέσω του πλαισίου NIO (New I/O). εισήγαγε το NIOFileChannelκαιSocketChannel και άλλες κλάσεις, οι οποίες παρέχουν πιο αποτελεσματικές λειτουργίες I/O. ΕΙΔΙΚΑ,FileChannel.transferTo()καιFileChannel.transferFrom()Οι μέθοδοι μπορούν να μεταφέρουν δεδομένα απευθείας από ένα κανάλι αρχείου σε ένα κανάλι υποδοχής ή αντίστροφα χωρίς να φορτώνουν τα δεδομένα σε ένα buffer, επιτυγχάνοντας έτσι μηδενικό αντίγραφο.

Για παράδειγμα, ας υποθέσουμε ότι πρέπει να στείλετε τα περιεχόμενα ενός μεγάλου αρχείου στο δίκτυο Η παραδοσιακή προσέγγιση είναι να διαβάσετε πρώτα τα περιεχόμενα του αρχείου σε ένα buffer και μετά να γράψετε τα περιεχόμενα του buffer στο δίκτυο. Αυτό περιλαμβάνει δύο λειτουργίες αντιγραφής: μία από το δίσκο στο buffer και μία άλλη από την προσωρινή μνήμη στο δίκτυο.κατά τη χρήσηtransferTo()Κατά τη χρήση αυτής της μεθόδου, τα δεδομένα μπορούν να μεταφερθούν απευθείας από το δίσκο στο δίκτυο χωρίς την ανάγκη ενδιάμεσου buffer, που μειώνει τον αριθμό των αντιγράφων και επιτυγχάνει μηδενικό αντίγραφο.

Ένα παράδειγμα που χρησιμοποιεί το ByteBuffer:

ByteBufferκαι άλλεςBufferτάξη (όπωςCharBufferShortBufferκ.λπ.) παρέχουν buffer που μπορούν να γεμίσουν ή να αδειάσουν χωρίς να εμπλέκεται άμεσα ένα αντίγραφο μεταξύ του χώρου χρήστη και του χώρου του πυρήνα.ByteBufferΜπορεί να χρησιμοποιηθεί άμεσα ή έμμεσα στην τεχνολογία μηδενικής αντιγραφής:

  1. Απευθείας προσωρινή μνήμηByteBuffer.allocateDirect(size)ΔημιουργήθηκεByteBuffer Τα στιγμιότυπα αντιστοιχίζονται απευθείας στη φυσική μνήμη, παρακάμπτοντας το σωρό Java.Όταν ένα τέτοιο buffer συγκρίνεται μεFileChannelήSocketChannel Όταν χρησιμοποιούνται μαζί, τα δεδομένα μπορούν να μεταφερθούν απευθείας μεταξύ φυσικής μνήμης και συσκευών υλικού χωρίς την ανάγκη πρόσθετων αντιγράφων μέσω του σωρού Java. Αυτό επιτρέπει την πραγματική μηδενική αντιγραφή σε ορισμένες πλατφόρμες.
  2. χρήσηFileChannelτουtransferTo()καιtransferFrom(): Αυτές οι μέθοδοι επιτρέπουν την απευθείας αποθήκευση δεδομένωνFileChannelκαιSocketChannelμεταδίδεται μεταξύByteBuffer ως ενδιάμεσος. Αυτό σημαίνει ότι τα δεδομένα μπορούν να μεταφερθούν απευθείας από το δίσκο στο δίκτυο ή το αντίστροφο χωρίς να χρειάζεται να αντιγραφούν μεταξύ του χώρου χρήστη και του χώρου του πυρήνα.
  3. χρήσηByteBufferτουwrap()μέθοδοςwrap()Η μέθοδος σάς επιτρέπει να τυλίξετε έναν υπάρχοντα πίνακα byte ή άλλο buffer σε έναByteBuffer , επομένως δεν χρειάζεται να αντιγράψετε τα δεδομένα σε νέο buffer. Αυτό είναι χρήσιμο για την αποφυγή περιττής αντιγραφής δεδομένων.
  4. χρήσηByteBufferτουslice()μέθοδοςslice() Η μέθοδος δημιουργεί μια προβολή του buffer χωρίς να αντιγράφει τα υποκείμενα δεδομένα.Αυτό σημαίνει ότι ένα μεγάλοByteBufferΔιαχωρισμός σε πολλά μικρότερα buffer χωρίς αντιγραφή δεδομένων.

Συνδυάστε το ByteBuffer με το FileChannel:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class ZeroCopyExample {
    public static void main(String[] args) {
        Path path = Path.of("example.txt");
        try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            long transferred = fileChannel.transferTo(0, fileChannel.size(), System.out);
            System.out.println("Transferred bytes: " + transferred);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Ειδοποίηση:

Θα πρέπει να σημειώσουμε ότι στην πραγματικότητα, δεν υπάρχει πλήρες μηδενικό αντίγραφο Το μηδενικό αντίγραφο που αναφέρεται εδώ είναι μόνο για την ίδια την εφαρμογή μας, η οποία δεν έχει αντίγραφο σε επίπεδο χρήστη. Αλλά ακόμη και σε επίπεδο χρήστη, είναι αδύνατο να μην υπάρχουν καθόλου λειτουργίες αντιγραφής, αλλά να μειωθούν όσο το δυνατόν περισσότερο τα αντίγραφα, επομένως, μπορούμε να καταλάβουμε ότι ο όρος μηδενικό αντίγραφο αναφέρεται στην τεχνολογία μείωσης του αριθμού των αντιγράφων δεδομένων. και δεν σημαίνει ότι δεν υπάρχει λειτουργία αληθινής αντιγραφής.