/ Forside / Teknologi / Udvikling / Java / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
Java
#NavnPoint
molokyle 3688
Klaudi 855
strarup 740
Forvirret 660
gøgeungen 500
Teil 373
Stouenberg 360
vnc 360
pmbruun 341
10  mccracken 320
NIO: SelectionKey.interestOps(int) blokker~
Fra : Daniel Jacobsen


Dato : 18-08-03 14:58

Hej

Jeg har lavet en multiplayer-server, der håndtere en hel del klienter på
samme tid. Indtil fornyelig kørte jeg kun serveren på Linux, men blev nødt
til at hoste på Windows 2K Server - et underligt og kritisk problem dukkede
op.

java.nio anvendes til håndtering af klient-kommunikationen. Serveren har én
Selector og når en SelectionKey er klar til skrive eller læse tager
Selector'en en Worker fra en pool og overrækker den aktuelle SelectionKey,
hvorefter worker'en tager sig af læsningen eller skrivningen.

Når serveren sender data til en klient køres denne metode
(Client.sendMessage):

public void sendMessage(Message m) throws CancelledKeyException {
sendQueue.add(m);
if (connected && key.isValid()) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
key.selector().wakeup();
}
}

Problemet synes at være denne linie:

key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);

....som 50% af gangen blokkerer i 1 - 4 minutter, hvilket IKKE er
acceptabelt. Dette problem forekommer slet ikke under Linux.

Nogen der kender en løsning ?

// Daniel J.



 
 
Nikolaj Hansen (21-08-2003)
Kommentar
Fra : Nikolaj Hansen


Dato : 21-08-03 23:35

>key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);


prøv lige at sætte et enkelt kald ind til

key.interestOps();

Og se hvor lang tid det tager. Mon ikke det på en eller anden måde er
rekusiviteten på øverste linje, der tager tid?

Jeg kunne forestille mig at der er langt flere keys på den ene platform end
den anden. Eksekveringstiden vil således stige eksponentielt ift. antallet
af keys da du har et rekursivt kald.



Daniel Jacobsen (22-08-2003)
Kommentar
Fra : Daniel Jacobsen


Dato : 22-08-03 00:20

> prøv lige at sætte et enkelt kald ind til
>
> key.interestOps();
>
> Og se hvor lang tid det tager. Mon ikke det på en eller anden måde er
> rekusiviteten på øverste linje, der tager tid?

Det kan godt være, men det giver absolut ingen problemer under Linux og kan
den blokkere i op til 4 minutter, selvom der kun er ca. 5 klienter på
serveren !



Nikolaj Hansen (22-08-2003)
Kommentar
Fra : Nikolaj Hansen


Dato : 22-08-03 00:38

ja, men netop I/O er jo "native" på et eller andet plan. Og java skal på et
tidspunkt ud at bede systemet om nogle netværks ressourcer, ligesom det skal
ud at bede filsystemet om ressourcer en gang i mellem.

Så på disse punkter kan java sagtens opføre sig forskelligt performance wise
i mellem platforme.



Daniel Jacobsen (22-08-2003)
Kommentar
Fra : Daniel Jacobsen


Dato : 22-08-03 07:48

> ja, men netop I/O er jo "native" på et eller andet plan. Og java skal på
et
> tidspunkt ud at bede systemet om nogle netværks ressourcer, ligesom det
skal
> ud at bede filsystemet om ressourcer en gang i mellem.
>
> Så på disse punkter kan java sagtens opføre sig forskelligt performance
wise
> i mellem platforme.

Helt klart, men da 4 minutters umotiveret ventetid aldrig kan blive
acceptabelt i et høj-performance system, må løsningen være slet ikke at
bruge linien:

key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);

....eller kun køre systemet på Linux, hvilket ikke altid er et alternativ.

Løsningen er blevet, i stedet for at notificere en anden tråd om at nu har
denne klient noget der skal sendes, blot at sende beskeden med det samme:

public void sendMessage(Message m) {
try {
String out = m.toString();
out = m.toString()+terminater;
sendBuf.put(out.getBytes());
sendBuf.flip();
while (sendBuf.hasRemaining()) {
channel.write(sendBuf);
}
sendBuf.clear();
} catch (IOException ioe) {
...
}
}

Det reducerer performance, men til gengæld virker det på windows.

// Daniel J.



Filip Larsen (22-08-2003)
Kommentar
Fra : Filip Larsen


Dato : 22-08-03 08:32

Daniel Jacobsen skrev

> Når serveren sender data til en klient køres denne metode
> (Client.sendMessage):
>
> public void sendMessage(Message m) throws CancelledKeyException {
> sendQueue.add(m);
> if (connected && key.isValid()) {
> key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
> key.selector().wakeup();
> }
> }
>
> Problemet synes at være denne linie:
>
> key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
>
> ...som 50% af gangen blokkerer i 1 - 4 minutter, hvilket IKKE er
> acceptabelt. Dette problem forekommer slet ikke under Linux.

Jeg har ikke særlig meget erfaring med nio endnu, men iflg. dokumentationen
er det
platformsafhængigt om SelecionKey.interestOps(int) kan finde på at blokere.
Måske blokerer kaldet under Windows hvis en anden tråd blokerer selectoren,
og i så fald kan det måske hjælpe at vække selectoren før du sætter
interestOps??

En anden mulighed kunne måske være at vente med at sætte OP_WRITE indtil en
non-blocking write rent faktisk returnerer uden at have skrevet hele
bufferen. For eksempel kan du i din hovedløkke, før kaldet til
selector.select, skrive til alle de channels der har noget i deres sendQueue
og for hver channel sætte OP_WRITE når og kun når ikke hele bufferen blev
skrevet.


--
Filip Larsen



Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408924
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste