Mi riferisco allo standard POSIX selezionare e sondare le chiamate API C del sistema.
Mi riferisco allo standard POSIX selezionare e sondare le chiamate API C del sistema.
Risposte:
Penso che questo risponda alla tua domanda:
Da Richard Stevens (rstevens@noao.edu):
La differenza di base è che fd_set di select () è una maschera di bit e quindi ha una dimensione fissa. Sarebbe possibile che il kernel non limiti questa dimensione quando il kernel viene compilato, consentendo all'applicazione di definire FD_SETSIZE come vuole (come i commenti nell'intestazione del sistema implicano oggi) ma ci vuole più lavoro. 4.4 Il kernel diBSD e la funzione di libreria Solaris hanno entrambi questo limite. Ma vedo che BSD / OS 2.1 è stato ora codificato per evitare questo limite, quindi è fattibile, solo una piccola questione di programmazione. :-) Qualcuno dovrebbe presentare una segnalazione di bug di Solaris su questo, e vedere se è mai stato corretto.
Con poll (), tuttavia, l'utente deve allocare un array di strutture pollfd e passare il numero di voci in questo array, quindi non ci sono limiti fondamentali. Come osserva Casper, un numero inferiore di sistemi ha poll () rispetto a select, quindi quest'ultimo è più portatile. Inoltre, con le implementazioni originali (SVR3) non è stato possibile impostare il descrittore su -1 per dire al kernel di ignorare una voce nella struttura pollfd, che ha reso difficile rimuovere le voci dall'array; SVR4 aggira questo. Personalmente, utilizzo sempre select () e raramente poll (), perché porto anche il mio codice su ambienti BSD. Qualcuno potrebbe scrivere un'implementazione di poll () che utilizza select (), per questi ambienti, ma non ne ho mai visto uno. Sia select () che poll () vengono standardizzati da POSIX 1003.1g.
L'e-mail citata sopra ha almeno il 2001; il poll()
comando è ora (2017) supportato su tutti i sistemi operativi moderni, incluso BSD. In effetti, alcune persone credono che select()
dovrebbe essere deprecato . Opinioni a parte, i problemi di portabilità in giro poll()
non sono più una preoccupazione per i sistemi moderni. Inoltre, epoll()
da allora è stato sviluppato (puoi leggere la pagina man ) e continua a crescere in popolarità.
Per lo sviluppo moderno probabilmente non vuoi usare select()
, anche se non c'è nulla di esplicitamente sbagliato in esso. poll()
, ed è l'evoluzione più moderna epoll()
, fornisce le stesse caratteristiche (e altro) come select()
senza soffrire dei limiti in essa contenuti.
select
o poll
:(
La select()
chiamata è di creare tre bitmasks a marchio che prese e descrittori di file che si desidera vedere per la lettura, la scrittura, e gli errori, e poi i marchi del sistema operativo quali infatti hanno avuto qualche tipo di attività; poll()
hai creato un elenco di ID descrittori e il sistema operativo contrassegna ciascuno di essi con il tipo di evento che si è verificato.
Il select()
metodo è piuttosto goffo e inefficiente.
In genere ci sono più di mille potenziali descrittori di file disponibili per un processo. Se un processo di lunga durata ha solo pochi descrittori aperti, ma almeno uno di essi è stato assegnato un numero elevato, allora la maschera di bit passata select()
deve essere abbastanza grande da accogliere quel descrittore più alto, quindi intere gamme di centinaia di bit saranno essere disinserito dal fatto che il sistema operativo deve eseguire il ciclo ad ogni select()
chiamata solo per scoprire che non sono impostati.
Una volta select()
restituito, il chiamante deve scorrere su tutte e tre le maschere di bit per determinare quali eventi hanno avuto luogo. In molte applicazioni tipiche solo uno o due descrittori di file riceveranno nuovo traffico in qualsiasi momento, tuttavia tutte e tre le maschere di bit devono essere lette fino alla fine per scoprire quali descrittori sono.
Poiché il sistema operativo ti segnala l'attività riscrivendo le maschere di bit, sono rovinate e non sono più contrassegnate con l'elenco di descrittori di file che desideri ascoltare. O devi ricostruire l'intera maschera di bit da qualche altra lista che tieni in memoria, oppure devi conservare una copia duplicata di ciascuna maschera di bit e memcpy()
il blocco di dati sopra le maschere di bit rovinate dopo ogni select()
chiamata.
Così la poll()
approccio funziona molto meglio perché puoi continuare a riutilizzare la stessa struttura di dati.
In effetti, poll()
ha ispirato un altro meccanismo nei moderni kernel Linux:epoll()
che migliora ancora di più il meccanismo per consentire un ulteriore salto di scalabilità, poiché i server di oggi vogliono spesso gestire decine di migliaia di connessioni contemporaneamente. Questa è una buona introduzione allo sforzo:
http://scotdoyle.com/python-epoll-howto.html
Mentre questo link ha alcuni bei grafici che mostrano i vantaggi di epoll()
(noterai che select()
a questo punto è considerato così inefficiente e vecchio stile che non ha nemmeno una linea su questi grafici!):
http://lse.sourceforge.net/epoll/index.html
Aggiornamento: ecco un'altra domanda Stack Overflow, la cui risposta fornisce ancora più dettagli sulle differenze:
Entrambi sono lenti e per lo più uguali , ma di dimensioni diverse e alcune caratteristiche!
Quando scrivi un iteratore, devi copiare il set di select
ogni volta! Mentre poll
ha risolto questo tipo di problema per avere un bellissimo codice. Un'altra differenza è che poll
può gestire più di 1024 descrittori di file (FD) per impostazione predefinita. poll
può gestire eventi diversi per rendere il programma più leggibile invece di avere molte variabili per gestire questo tipo di lavoro. Le operazioni in poll
e select
sono lineari e lente a causa di numerosi controlli.