نظام Go like المتزامن + مكتبات الشبكات/http لـ Swift التي تعمل على Linux وMac.
السبب وراء بدء هذا المشروع هو أنني شعرت أنه من الصعب جدًا التعامل مع IO غير المتزامن مع Swift في المشروع المسمى Slimane الذي قمت بإنشائه مسبقًا. في النموذج غير المتزامن في Swift، نحتاج في كثير من الأحيان إلى استخدام قائمة الالتقاط بشكل جيد لعمليات الإغلاق وفي بعض الأحيان الاحتفاظ بالكائن (الاتصال وما إلى ذلك ..) لتجنب تحريره بواسطة ARC. ثم اعتقدت أن آلية Go المتزامنة/المتوازية والمتزامنة هي نموذج مناسب للمرحلة الحالية من Swift (إذا كنت تريد كتابة الخادم على جهاز MultiCore). نظرًا لأنه يمكننا بسهولة إجراء عمليات غير متزامنة بدون سلاسل رد الاتصال، فيمكننا استخدام Full Cores مع بناء الجملة البسيط وسهولة مشاركة الذاكرة عبر القناة بين سلسلة رسائل وسلسلة رسائل.
(Prorsum ليس Goroutine. فهو لا يحتوي على Corotuines ويتم تبديل السياق على جانب نظام التشغيل. إنه يحتوي فقط على آلية ذاكرة مشتركة آمنة للخيط (تعمل على GCD) مستوحاة بشكل كبير من Go.)
إن بنية خادم HTTP الخاص بـ Prorsum هي معالج رئيسي يحركه الحدث + معالج طلب متعدد الخيوط. في DispatchQueue، يمكنك كتابة إدخال/إخراج غير متزامن باستخدام بناء جملة متزامن باستخدام go()
+ Channel<Element>
.
من السهل جعل الرموز تحل C10K دون عمليات الاسترجاعات.
+-----------------+
|-- | Request Handler |
| +-----------------+
+--------+ | +-----------------+
----- TCP ---- | master |---Dispatch Queue---|-- | Request Handler |
+--------+ | +-----------------+
| +-----------------+
|-- | Request Handler |
+-----------------+
يدعم Currenty Prorsum SPM فقط.
import PackageDescription
let package = Package (
name : " MyApp " ,
dependencies : [
. Package ( url : " https://github.com/noppoMan/Prorsum.git " , majorVersion : 0 , minor : 1 )
]
)
غير معتمد حتى الآن
غير معتمد حتى الآن
go
go هو اسم مستعار لـ DispatchQueue().async { }
func asyncTask ( ) {
print ( Thread . current )
}
go ( asyncTask ( ) )
go {
print ( Thread . current )
}
gomain {
print ( Thread . current ) // back to the main thread
}
WaitGroup
تنتظر WaitGroup انتهاء مجموعة من عمليات GCD. تستدعي عملية GCD الرئيسية "إضافة" لتعيين عدد عمليات GCD التي سيتم انتظارها. ثم يتم تشغيل كل عملية من عمليات GCD واستدعاء "تم" عند الانتهاء. وفي الوقت نفسه، يمكن استخدام الانتظار للحظر حتى تنتهي جميع عمليات GCD.
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>
القنوات هي الأنابيب التي تربط العمليات المتزامنة. يمكنك إرسال القيم إلى القنوات من إحدى عمليات GCD واستقبال هذه القيم في عملية GCD أخرى.
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
يتيح بيان التحديد لـ BlockOperation
الانتظار لعمليات اتصال متعددة.
let magicCh = Channel < String > . make ( capacity : 1 )
go {
try ! magicCh . send ( " Obliviate " )
}
select {
when ( magicCh ) {
print ( $0 )
}
otherwise {
print ( " otherwise " )
}
}
forSelect
بشكل عام، تحتاج إلى التفاف التحديد داخل حلقة while. لتسهيل العمل مع هذا النمط، يمكنك استخدام forSelect
. سوف يتكرر forSelect حتى يتم استدعاء done()
.
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
فيما يلي مثال لخادم 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 بموجب ترخيص MIT. راجع الترخيص للحصول على التفاصيل.