2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Kuvaa NIO:n perustiedot ava-tasolla peruskatsausta varten
Javassa NIO (Non-blocking I/O tai New I/O) on Java SE 1.4:ssä ja myöhemmissä versioissa esitelty uusi syöttö/tulostustoimintojen API.
Perinteiseen IO-malliin verrattuna se tarjoaa paremman tehokkuuden ja paremmat samanaikaiset prosessointiominaisuudet. NIO:n keskeinen ominaisuus on sen estävä ominaisuus, jonka avulla yksi säie voi hallita useita I/O-kanavia, mikä parantaa huomattavasti sovellusten suorituskykyä korkean samanaikaisuuden skenaarioissa.
Java NIO:n käyttöskenaario sopii erityisen hyvin tilanteisiin, joissa on käsiteltävä suuri määrä samanaikaisia yhteyksiä Esimerkiksi verkkopalvelimessa yksi säie voi hallita tuhansia asiakasyhteyksiä ilman, että jokaiselle yhteydelle on varattava erillistä säiettä. Voi vähentää merkittävästi järjestelmän resurssien kulutusta ja parantaa käsittelyominaisuuksia
Kanava on tietovirran väline Java NIO:ssa. Se on kaksisuuntainen ja sitä voidaan käyttää tietojen lukemiseen tai kirjoittamiseen. Kanavien tärkein etu on, että ne eivät estä, mikä tarkoittaa, että yksi säie voi hallita useita kanavia. Pääkanavatyyppejä ovat:
FileChannel
: Käytetään tiedostojen luku- ja kirjoitustoimintoihin. Sitä voidaan käyttää tietojen kirjoittamiseen puskurista tiedostoon tai tietojen lukemiseen tiedostosta puskuriin.SocketChannel
: Käytetään TCP-yhteyksiin verkkoviestinnässä, ja sitä voidaan käyttää tietojen lukemiseen ja kirjoittamiseen.ServerSocketChannel
: Käytetään uusien SocketChannel-yhteyksien hyväksymiseen, kuten perinteinen ServerSocket.DatagramChannel
: Käytetään UDP-viestintään, joka voi lähettää ja vastaanottaa datagrammeja.Puskuri on objekti, jota käytetään tietojen tallentamiseen NIO:ssa. Se on tavutaulukko, joka voi kirjoittaa tietoja ja lukea tietoja siitä. Puskurilla on tietty kapasiteetti ja kaksi tärkeää ominaisuutta: sijainti ja raja.
Puskurien päätyypit ovatByteBuffer
、CharBuffer
、ShortBuffer
、IntBuffer
、LongBuffer
、FloatBuffer
jaDoubleBuffer
, jokainen tyyppi vastaa primitiivistä tietotyyppiä.
Valitsin on NIO:n multiplekseri, jonka avulla yksi säie voi seurata tapahtumia useilta kanavilta, kuten lukea, kirjoittaa, yhdistää ja vastaanottaa tapahtumia. Valitsin ilmoittaa sovellukselle, kun jokin kanavista on valmis I/O-toimintoihin. Valitsimien käyttö parantaa huomattavasti verkkosovellusten samanaikaisuuden käsittelyominaisuuksia, koska jokaiselle yhteydelle ei tarvitse luoda säiettä.
Tärkeimmät valintamenetelmät ovat:
select()
: Estää, kunnes vähintään yksi kanava on valmis I/O-toimintoja varten.selectedKeys()
: Palauttaa joukon, joka sisältää kaikkien valmisteltujen kanavien SelectionKey-objektit.wakeup()
: Keskeytys estettyselect()
siirtää.SelectionKey
Se on valitsimien ja kanavien välinen yhteys. Se edustaa kanavan rekisteröintitilaa valitsimessa, mukaan lukien kanavat, valitsijat, kiinnostuneet tapahtumakokoelmat ja valmiit tapahtumakokoelmat.
Tämä on perinteisin I/O-malli Javassa perinteiset Socket- ja ServerSocket-API:t perustuvat I/O:n estoon. Tässä tilassa, kun säie aloittaa luku- tai kirjoitustoiminnon, säie estetään, kunnes I/O-toiminto on valmis. Jos lukutoimintoa varten ei ole luettavaa dataa tai kirjoitustoimintoa ei voida suorittaa heti loppuun, säie odottaa, kunnes toiminto on valmis.
Ominaisuudet:
Estoton I/O on osa Java NIO (New I/O) -kehystä, jonka avulla säikeet voivat aloittaa luku- ja kirjoitustoiminnot ilman, että niitä estetään. Jos lukutoimintoa varten ei ole luettavaa dataa tai kirjoitustoimintoa ei voida suorittaa heti loppuun, säiettä ei keskeytetä ja se voi jatkaa muiden tehtävien suorittamista.
Ominaisuudet:
Multipleksoinnilla on tarkoitus valvoa useita tiedostokuvaajia samanaikaisesti yhden säikeen kautta ja toimia vain kuvaajan kanssa, kun se on valmis (tavallisesti tarkoittaa, että tiedot ovat luettavissa tai kirjoituspuskuri on kirjoitettava). Javassa käytetään valitsimia multipleksoinnin toteuttamiseen.
Ominaisuudet:
Ilmoitus:
Käytännön sovelluksissa estostamatonta I/O:ta käytetään usein multipleksoinnin yhteydessä. Palvelin voi esimerkiksi käyttää valitsinta useiden SocketChannelien valvontaan. Kun SocketChannelilla on tietoja, joita voidaan lukea tai kirjoittaa, Selector ilmoittaa siitä palvelimelle, ja palvelin käsittelee tämän tietyn SocketChannelin estävällä tavalla.
Javassa Stream ja Channel ovat kaksi erilaista tapaa käsitellä tietovirtoja. Ne kuuluvat Java-standardin IO-kirjastoon ja vastaavasti NIO-kirjastoon. Tässä on yksityiskohtainen vertailu kahdesta käsitteestä:
Stream on osa Javan standardia IO (blocking IO) -mallia, joka tarjoaa tavan lukea ja kirjoittaa tietoja peräkkäin. Stream on jaettu kahteen tyyppiin: InputStream ja OutputStream, joita käytetään tietojen lukemiseen ja kirjoittamiseen.Nämä virrat voivat olla tavuvirtoja (esimInputStream
, OutputStream
) tai merkkivirta (esimReader
, Writer
)。
Ominaisuudet:
close()
tapa vapauttaa resursseja.Java 7:stä alkaen try-with-resources -käsky voi sulkea toteutuksen automaattisestiAutoCloseable
Käyttöliittymäresurssit, mukaan lukien Stream. Kanava on osa Java NIO (New IO) -mallia, joka tarjoaa korkeamman tason abstraktiota kuin Stream, mikä mahdollistaa tehokkaamman tietojenkäsittelyn. Kanavat voivat olla kaksisuuntaisia, mikä tarkoittaa, että niitä voidaan käyttää tietojen lukemiseen ja kirjoittamiseen.Pääkanavatyyppejä ovat mmFileChannel
、SocketChannel
、ServerSocketChannel
jaDatagramChannel
。
Ominaisuudet:
Tee yhteenveto
Javassa I/O-toimintamallit voidaan luokitella kahden ulottuvuuden perusteella: synkroninen/asynkroninen ja estävä/ei-esto.
määritelmä : Synkroninen esto I/O on perinteisin I/O-malli. Tämä tarkoittaa, että säie ei voi suorittaa muita tehtäviä ennen kuin toiminto on valmis.
ominaisuudet:
InputStream
、OutputStream
、Socket
jaServerSocket
näkymä.Esimerkki:
Käytä perinteistäInputStream
jaOutputStream
Tiedostojen lukeminen ja kirjoittaminen:
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();
}
}
}
määritelmä : Synkronisessa ei-estossa I/O:ssa säiettä ei lukita I/O-toiminnon kutsumisen jälkeen. Jos toimintoa ei voida suorittaa heti loppuun, menetelmä palaa välittömästi, yleensä palauttaen erikoisarvon (kuten -1 tai 0) tai heittämällä poikkeuksen osoittamaan, että toimintoa ei ole suoritettu loppuun.
ominaisuudet:
Channels
jaBuffers
, soittamallaconfigureBlocking(false)
Aseta kanava estotilaan.Esimerkki:
NIO:n käyttöFileChannel
Lukemisen ja kirjoittamisen estäminen:
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();
}
}
}
määritelmä: Synkronisen multipleksoidun I/O-mallin käyttöSelector
(valitsin) useiden seuraamiseenChannel
tapahtuma.Kun lanka kutsuuSelector.select()
, se estetään, kunnes niitä on vähintään yksiChannel
Tapahtumia (kuten luettavissa, kirjoitettavissa, yhteyspyyntö jne.) tapahtuu.
ominaisuudet:
Channel
, parantaa samanaikaisuutta.Selector
jaSelectionKey
Mekanismi, joka pystyy käsittelemään tehokkaasti useita samanaikaisia yhteyksiä.Esimerkki:
NIO:n käyttöFileChannel
Lukemisen ja kirjoittamisen estäminen:
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();
}
}
}
}
}
määritelmä : Asynkronisessa ei-estossa I/O-mallissa säie palaa välittömästi I/O-toiminnon aloittamisen jälkeen odottamatta toiminnon valmistumista. Kun toiminto on valmis, säiettä ilmoitetaan asynkronisesti takaisinsoittotoiminnon tai tapahtumailmoituksen kautta.
ominaisuudet:
AsynchronousChannel
Käyttöliittymä ja sen alaluokan toteutus, kutenAsynchronousFileChannel
jaAsynchronousSocketChannel
。Esimerkki:
NIO:n käyttöAsynchronousFileChannel
Suorita asynkroninen tiedostojen lukeminen ja kirjoittaminen:
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();
}
}
Huomautus: Asynkroninen malli vaatii tukea taustalla olevalta käyttöjärjestelmältä (ydin)
määritelmä : Teoriassa tätä mallia ei ole olemassa, koska "asynkroninen" tarkoittaa, että toiminto suoritetaan taustalla eikä säiettä ole estetty. Siksi asynkroninen esto I/O on ristiriitainen käsite, eikä sitä tule esiin käytännössä.
Sopivan I/O-mallin valitseminen on ratkaisevan tärkeää suorituskyvyn ja resurssienhallinnan kannalta. Korkean samanaikaisuuden skenaarioissa synkroniset estävät I/O-mallit tai synkroniset multipleksoidut I/O-mallit ovat yleisiä vaihtoehtoja skenaarioissa, jotka vaativat äärimmäistä suorituskykyä ja vastenopeutta, asynkroninen ei-esto-I/O-malli on ensimmäinen valinta.
Zero-Copy -konsepti
Zero-copy-tekniikka tarkoittaa, että tiedonsiirron aikana paikasta toiseen tietoja ei tarvitse kopioida käyttäjätilan ja ydintilan välillä tai ainakin vähentää tällaisten kopioiden määrää, mikä parantaa tiedonsiirron tehokkuutta. järjestelmä. Perinteisissä I/O-toiminnoissa, kun dataa luetaan verkosta tai levyltä, se kopioidaan ensin ydintilan puskuriin ja sitten ydintilasta käyttäjätilan puskuriin. Päinvastoin, nollakopiossa data voidaan käsitellä suoraan ydintilassa tai siirtää suoraan ydintilasta verkkolaitteeseen, mikä vähentää prosessorin kopiointitoimintaa, vähentää järjestelmän ylikuormitusta ja parantaa tiedonsiirron tehokkuutta.
Nollakopion lähde
Nollakopion käsite ilmestyi ensimmäisen kerran käyttöjärjestelmän suunnittelussa, ja sen tavoitteena oli ratkaista perinteisten I/O-toimintojen tiedon kopioimisen aiheuttama suorituskyky pullonkaula. Varhaisissa tietokonejärjestelmissä kaikki I/O-toiminnot vaativat useita datakopioita käyttäjätilan ja ydintilan välillä. Tästä tuli vähitellen suorituskyvyn pullonkaula, kun nopeat verkot ja suuren kapasiteetin levyt yleistyivät.
Tärkeimmät tekniset kohdat
Käyttöönotto Javassa:
Java tukee nollakopiotekniikkaa NIO (New I/O) -kehyksen kautta. NIO esitteliFileChannel
jaSocketChannel
ja muut luokat, jotka tarjoavat tehokkaamman I/O-toiminnan. Erityisesti,FileChannel.transferTo()
jaFileChannel.transferFrom()
Menetelmillä voidaan siirtää tietoja suoraan tiedostokanavasta socket-kanavalle tai päinvastoin lataamatta dataa puskuriin, jolloin saadaan nollakopio.
Oletetaan esimerkiksi, että sinun on lähetettävä suuren tiedoston sisältö verkkoon. Perinteinen lähestymistapa on ensin lukea tiedoston sisältö puskuriin ja kirjoittaa puskurin sisältö verkkoon. Tämä sisältää kaksi kopiointitoimintoa: yksi levyltä puskuriin ja toinen puskurista verkkoon.käytön aikanatransferTo()
Tätä menetelmää käytettäessä tiedot voidaan siirtää suoraan levyltä verkkoon ilman välipuskuria, mikä vähentää kopioiden määrää ja saavuttaa nollakopion.
Esimerkki ByteBufferista:
ByteBuffer
ja muutBuffer
luokka (esimCharBuffer
,ShortBuffer
jne.) tarjoavat puskureita, jotka voidaan täyttää tai tyhjentää ilman, että käyttäjätilan ja ydintilan välillä tehdään kopiota.ByteBuffer
Voidaan käyttää suoraan tai epäsuorasti nollakopiotekniikassa:
ByteBuffer.allocateDirect(size)
LuotuByteBuffer
Instanssit kartoitetaan suoraan fyysiseen muistiin Java-keon ohittaen.Kun tällaista puskuria verrataanFileChannel
taiSocketChannel
Yhdessä käytettynä tiedot voidaan siirtää suoraan fyysisen muistin ja laitteiston välillä ilman lisäkopioita Java-keon kautta. Tämä mahdollistaa todellisen nollakopion joillakin alustoilla.FileChannel
/transferTo()
jatransferFrom()
: Nämä menetelmät mahdollistavat tietojen tallentamisen suoraanFileChannel
jaSocketChannel
välitetäänByteBuffer
välittäjänä. Tämä tarkoittaa, että tietoja voidaan siirtää suoraan levyltä verkkoon tai päinvastoin ilman, että niitä tarvitsee kopioida käyttäjätilan ja ydintilan välillä.ByteBuffer
/wrap()
menetelmä:wrap()
-menetelmän avulla voit kääriä olemassa olevan tavutaulukon tai muun puskurin aByteBuffer
, joten tietoja ei tarvitse kopioida uuteen puskuriin. Tämä on hyödyllistä tietojen tarpeettoman kopioimisen välttämiseksi.ByteBuffer
/slice()
menetelmä:slice()
menetelmä luo näkymän puskurista kopioimatta taustalla olevia tietoja.Tämä tarkoittaa, että suuriByteBuffer
Jaa useisiin pienempiin puskureihin ilman tietojen kopioimista.Yhdistä ByteBuffer FileChannelin kanssa:
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();
}
}
}
Ilmoitus:
On huomattava, että itse asiassa ei ole olemassa täydellistä nollakopiota. Tässä mainittu nollakopio on vain itse sovelluksellemme, jolla ei ole käyttäjätason kopiota. Mutta jopa käyttäjätasolla on mahdotonta tehdä kopiointitoimintoja ollenkaan, vaan vähentää kopioita mahdollisimman paljon. Siksi voimme ymmärtää, että termi nollakopio viittaa itse asiassa datakopioiden määrän vähentämiseen. eikä se tarkoita, etteikö todellista kopiointitoimintoa olisi.