Sistem bersamaan + jaringan/perpustakaan http untuk Swift yang berfungsi di Linux dan Mac.
Alasan saya memulai proyek ini adalah karena saya merasa sangat sulit untuk menangani asynchronous io dengan Swift pada proyek bernama Slimane yang telah saya buat sebelumnya. Dalam paradigma Asynchronous di Swift, Kita perlu sering menggunakan daftar tangkapan dengan baik untuk penutupan dan terkadang mempertahankan objek (Koneksi dll.) untuk menghindari rilis oleh ARC. Lalu saya pikir mekanisme Go yang bersamaan/paralel dan sinkron adalah model yang cocok untuk tahap Swift saat ini (Jika Anda ingin menulis Server di Mesin MultiCore). Karena kita dapat dengan mudah melakukan operasi async tanpa rantai panggilan balik, dapat menggunakan Full Cores dengan sintaks sederhana dan mudah untuk berbagi memori melalui Saluran antara Thread dan Thread.
(Prorsum bukan Goroutine. Prorsum tidak memiliki Corotuine dan Pengalih Konteks dilakukan di sisi OS. Prorsum hanya memiliki mekanisme memori bersama yang aman untuk thread (Berfungsi di GCD) yang sangat terinspirasi oleh Go.)
Arsitektur Server HTTP Prorsum adalah master Berbasis Peristiwa + Penangan Permintaan Multithreading. Di DispatchQueue, Anda dapat menulis I/O asinkron dengan sintaksis sinkron dengan go()
+ Channel<Element>
.
Mudah untuk membuat kode menyelesaikan C10K tanpa panggilan balik.
+-----------------+
|-- | Request Handler |
| +-----------------+
+--------+ | +-----------------+
----- TCP ---- | master |---Dispatch Queue---|-- | Request Handler |
+--------+ | +-----------------+
| +-----------------+
|-- | Request Handler |
+-----------------+
Saat ini Prorsum hanya mendukung SPM.
import PackageDescription
let package = Package (
name : " MyApp " ,
dependencies : [
. Package ( url : " https://github.com/noppoMan/Prorsum.git " , majorVersion : 0 , minor : 1 )
]
)
Belum didukung
Belum didukung
go
go adalah alias dari DispatchQueue().async { }
func asyncTask ( ) {
print ( Thread . current )
}
go ( asyncTask ( ) )
go {
print ( Thread . current )
}
gomain {
print ( Thread . current ) // back to the main thread
}
WaitGroup
WaitGroup menunggu kumpulan operasi GCD selesai. Operasi GCD utama memanggil Tambah untuk mengatur jumlah operasi GCD yang harus ditunggu. Kemudian setiap operasi GCD dijalankan dan memanggil Selesai setelah selesai. Pada saat yang sama, Tunggu dapat digunakan untuk memblokir hingga semua operasi GCD selesai.
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>
Saluran adalah pipa-pipa yang menghubungkan operasi secara bersamaan. Anda dapat mengirimkan nilai ke saluran dari satu operasi GCD dan menerima nilai tersebut ke operasi GCD lainnya.
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
Pernyataan pilih memungkinkan BlockOperation
menunggu pada beberapa operasi komunikasi.
let magicCh = Channel < String > . make ( capacity : 1 )
go {
try ! magicCh . send ( " Obliviate " )
}
select {
when ( magicCh ) {
print ( $0 )
}
otherwise {
print ( " otherwise " )
}
}
forSelect
Umumnya Anda perlu membungkus pilihan di dalam loop while. Untuk mempermudah bekerja dengan pola ini Anda dapat menggunakan forSelect
. forSelect akan berulang hingga done()
dipanggil.
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
Berikut adalah Contoh Server Websocket Echo.
#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 dirilis di bawah lisensi MIT. Lihat LISENSI untuk detailnya.