Ein Go-ähnliches gleichzeitiges System + Netzwerk-/http-Bibliotheken für Swift, das unter Linux und Mac funktioniert.
Der Grund, warum ich dieses Projekt gestartet habe, ist, dass ich das Gefühl hatte, dass es sehr schwierig war, asynchrones IO mit Swift in dem Projekt namens Slimane zu handhaben, das ich zuvor erstellt hatte. Im asynchronen Paradigma in Swift müssen wir die Erfassungsliste häufig gut für Abschlüsse verwenden und manchmal das Objekt (Verbindung usw.) beibehalten, um eine Freigabe durch ARC zu vermeiden. Dann dachte ich, dass der gleichzeitige/parallele und synchrone Mechanismus von Go ein geeignetes Modell für die aktuelle Phase von Swift ist (wenn Sie Server auf der MultiCore-Maschine schreiben möchten). Da wir einfach asynchrone Vorgänge ohne Rückrufketten durchführen können, können wir mit der einfachen Syntax vollständige Kerne verwenden und den Speicher einfach über einen Kanal zwischen einem Thread und einem Thread teilen.
(Prorsum ist nicht Goroutine. Es verfügt nicht über Corotuines und der Kontextwechsel erfolgt auf der Betriebssystemseite. Es verfügt lediglich über einen Thread-sicheren Shared-Memory-Mechanismus (funktioniert auf dem GCD), der stark von Go inspiriert ist.)
Die HTTP-Server-Architektur von Prorsum ist ein ereignisgesteuerter Master + Multithreading-Request-Handler. In einer DispatchQueue können Sie mit go()
+ Channel<Element>
asynchrone E/A mit synchroner Syntax schreiben.
Einfach zu erstellende Codes lösen C10K ohne Rückrufe.
+-----------------+
|-- | Request Handler |
| +-----------------+
+--------+ | +-----------------+
----- TCP ---- | master |---Dispatch Queue---|-- | Request Handler |
+--------+ | +-----------------+
| +-----------------+
|-- | Request Handler |
+-----------------+
Derzeit unterstützt Prorsum nur SPM.
import PackageDescription
let package = Package (
name : " MyApp " ,
dependencies : [
. Package ( url : " https://github.com/noppoMan/Prorsum.git " , majorVersion : 0 , minor : 1 )
]
)
Noch nicht unterstützt
Noch nicht unterstützt
go
go ist ein Alias von DispatchQueue().async { }
func asyncTask ( ) {
print ( Thread . current )
}
go ( asyncTask ( ) )
go {
print ( Thread . current )
}
gomain {
print ( Thread . current ) // back to the main thread
}
WaitGroup
Eine WaitGroup wartet auf den Abschluss einer Sammlung von GCD-Vorgängen. Die Haupt-GCD-Operation ruft Add auf, um die Anzahl der GCD-Operationen festzulegen, auf die gewartet werden soll. Dann wird jeder der GCD-Vorgänge ausgeführt und ruft „Done“ auf, wenn er fertig ist. Gleichzeitig kann Wait zum Blockieren verwendet werden, bis alle GCD-Vorgänge abgeschlossen sind.
let wg = WaitGroup ( )
wg . add ( 1 )
go {
sleep ( 1 )
print ( " wg: 1 " )
wg . done ( )
}
wg . add ( 1 )
go {
sleep ( 1 )
print ( " wg: 2 " )
wg . done ( )
}
wg . wait ( ) // block unitle twice wg.done() is called.
print ( " wg done " )
Channel<Element>
Kanäle sind die Leitungen, die den gleichzeitigen Betrieb verbinden. Sie können Werte von einem GCD-Vorgang an Kanäle senden und diese Werte von einem anderen GCD-Vorgang empfangen.
let ch = Channel < String > . make ( capacity : 1 )
func asyncSend ( ) {
try ! ch . send ( " Expecto patronum! " )
}
go ( asyncSend ( ) ) // => Expecto patronum!
go {
try ! ch . send ( " Accio! " )
}
try ! ch . receive ( ) // => Accio!
ch . close ( )
select
Mit der SELECT-Anweisung kann eine BlockOperation
auf mehrere Kommunikationsvorgänge warten.
let magicCh = Channel < String > . make ( capacity : 1 )
go {
try ! magicCh . send ( " Obliviate " )
}
select {
when ( magicCh ) {
print ( $0 )
}
otherwise {
print ( " otherwise " )
}
}
forSelect
Im Allgemeinen müssen Sie die Auswahl in eine While-Schleife einbinden. Um die Arbeit mit diesem Muster zu erleichtern, können Sie forSelect
verwenden. forSelect wird eine Schleife durchlaufen, bis done()
aufgerufen wird.
let magicCh = Channel < String > . make ( capacity : 1 )
let doneCh = Channel < String > . make ( capacity : 1 )
go {
try ! magicCh . send ( " Crucio " )
try ! magicCh . send ( " Imperio " )
}
go {
try ! doneCh . send ( " Avada Kedavra! " )
}
forSelect { done in
when ( magicCh ) {
print ( $0 )
}
when ( doneCh ) {
done ( ) // break current loop
}
otherwise {
print ( " otherwise " )
}
}
import Prorsum
import Foundation
let server = try ! HTTPServer { ( request , writer ) in
do {
let response = Response (
headers : [ " Server " : " Prorsum Micro HTTP Server " ] ,
body : . buffer ( " hello " . data )
)
try writer . serialize ( response )
writer . close ( )
} catch {
fatalError ( " ( error ) " )
}
}
try ! server . bind ( host : " 0.0.0.0 " , port : 3000 )
print ( " Server listening at 0.0.0.0:3000 " )
try ! server . listen ( )
RunLoop . main . run ( ) //start run loop
import Prorsum
let url = URL ( string : " https://google.com " )
let client = try ! HTTPClient ( url : url! )
try ! client . open ( )
let response = try ! client . request ( )
print ( response )
// HTTP/1.1 200 OK
// Set-Cookie: NID=91=CPfJo7FsoC_HXmq7kLrs-e0DhR0lAaHcYc8GFxhazE5OXdc3uPvs22oz_UP3Bcd2mZDczDgtW80OrjC6JigVCGIhyhXSD7e1RA7rkinF3zxUNsDnAtagvs5pbZSjXuZE; expires=Sun, 04-Jun-2017 16:21:39 GMT; path=/; domain=.google.co.jp; HttpOnly
// Transfer-Encoding: chunked
// Accept-Ranges: none
// Date: Sat, 03 Dec 2016 16:21:39 GMT
// Content-Type: text/html; charset=Shift_JIS
// Expires: -1
// Alt-Svc: quic=":443"; ma=2592000; v="36,35,34"
// Cache-Control: private, max-age=0
// Server: gws
// X-XSS-Protection: 1; mode=block
// Vary: Accept-Encoding
// X-Frame-Options: SAMEORIGIN
// P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
#if os(Linux)
import Glibc
#else
import Darwin . C
#endif
import Prorsum
import Foundation
let server = try ! TCPServer { clientStream in
while !clientStream . isClosed {
let bytes = try ! clientStream . read ( )
try ! clientStream . write ( bytes )
clientStream . close ( )
}
}
// setup client
go {
sleep ( 1 )
let client = try ! TCPSocket ( )
try ! client . connect ( host : " 0.0.0.0 " , port : 3000 )
while !client . isClosed {
try ! client . write ( Array ( " hello " . utf8 ) )
let bytes = try ! client . recv ( )
if !bytes . isEmpty {
print ( String ( bytes : bytes , encoding : . utf8 ) )
}
}
server . terminate ( ) // terminate server
}
try ! server . bind ( host : " 0.0.0.0 " , port : 3000 )
try ! server . listen ( ) //start run loop
RunLoop . main . run ( ) //start run loop
Hier ist ein Websocket Echo Server-Beispiel.
#if os(Linux)
import Glibc
#else
import Darwin . C
#endif
import Foundation
import Prorsum
let server = try ! HTTPServer { ( request , writer ) in
do {
let response : Response
if request . isWebSocket {
response = try request . upgradeToWebSocket { request , websocket in
websocket . onText {
print ( " received: ( $0 ) " )
try ! websocket . send ( $0 )
}
}
} else {
response = Response (
headers : [ " Server " : " Prorsum Micro HTTP Server " ] ,
body : . buffer ( " hello " . data )
)
}
try writer . serialize ( response )
try response . upgradeConnection ? ( request , writer . stream )
writer . close ( )
} catch {
fatalError ( " ( error ) " )
}
}
try ! server . bind ( host : " 0.0.0.0 " , port : 8080 )
print ( " Server listening at 0.0.0.0:8080 " )
try ! server . listen ( )
RunLoop . main . run ( )
Prorsum wird unter der MIT-Lizenz veröffentlicht. Einzelheiten finden Sie unter LIZENZ.