التزامن الآمن على الطراز المباشر والمرونة لـ Scala على JVM. يتطلب JDK 21 و Scala 3. المناطق التي نود تغطيتها مع OX هي:
كل ما سبق يجب أن يسمح بملاحظة منطق العمل المنظم. نهدف إلى تمكين كتابة الكود البسيط الموجهة نحو التعبير في النمط الوظيفي. نود أن نبقي بناء الجملة العلوي إلى الحد الأدنى ، والحفاظ على آثار المكدس الصديقة للمطورين ، ودون المساومة على الأداء.
بعض مما سبق يتم تناوله بالفعل في واجهة برمجة التطبيقات ، بعضها سيأتي في المستقبل. نحن نحب مساعدتكم في تشكيل المشروع!
لاختبار الثور ، استخدم التبعية التالية ، باستخدام إما SBT:
" com.softwaremill.ox " %% " core " % " 0.5.3 "
أو Scala-Cli:
//> using dep " com.softwaremill.ox::core:0.5.3 "
الوثائق متوفرة على https://ox.softwaremill.com ، يمكن تصفح ScalAdocs على https://javadoc.io.
قم بتشغيل حسابين بالتوازي:
def computation1 : Int = { sleep( 2 .seconds); 1 }
def computation2 : String = { sleep( 1 .second); " 2 " }
val result1 : ( Int , String ) = par(computation1, computation2)
// (1, "2")
مهلة حساب:
def computation3 : Int = { sleep( 2 .seconds); 1 }
val result2 : Either [ Throwable , Int ] = either.catching(timeout( 1 .second)(computation3))
// `timeout` only completes once the loosing branch is interrupted & done
سباق اثنين من الحساب:
def computation4 : Int = { sleep( 2 .seconds); 1 }
def computation5 : Int = { sleep( 1 .second); 2 }
val result3 : Int = raceSuccess(computation4, computation5)
// as before, the loosing branch is interrupted & awaited before returning a result
التزامن منظم والإشراف:
// equivalent of par
supervised {
val f1 = fork { sleep( 2 .seconds); 1 }
val f2 = fork { sleep( 1 .second); 2 }
(f1.join(), f2.join())
}
معالجة الخطأ ضمن نطاق التزامن منظم:
supervised {
forkUser :
sleep( 1 .second)
println( " Hello! " )
forkUser :
sleep( 500 .millis)
throw new RuntimeException ( " boom! " )
}
// on exception, all other forks are interrupted ("let it crash")
// the scope ends & re-throws only when all forks complete (no "leftovers")
أعد إعادة حساب:
def computationR : Int = ???
retry( RetryConfig .backoff( 3 , 100 .millis, 5 .minutes, Jitter . Equal ))(computationR)
كرر الحساب:
def computationR : Int = ???
repeat( RepeatConfig .fixedRateForever( 100 .millis))(computationR)
تخصيص مورد في نطاق:
supervised {
val writer = useCloseableInScope( new java.io. PrintWriter ( " test.txt " ))
// ... use writer ...
} // writer is closed when the scope ends (successfully or with an error)
قم بإنشاء تطبيق يغلق بشكل نظيف عند مقاطعة Sigint/Sigterm:
object MyApp extends OxApp :
def run ( args : Vector [ String ])( using Ox ) : ExitCode =
// ... your app's code ...
// might use fork {} to create top-level background threads
ExitCode . Success
الممثلين البسيطين من النوع الآمن:
class Stateful { def increment ( delta : Int ) : Int = ??? }
supervised :
val ref = Actor .create( new Stateful )
// ref can be shared across forks, but only within the concurrency scope
ref.ask(_.increment( 5 ))
قم بإنشاء تدفق بسيط وتحويل باستخدام واجهة برمجة التطبيقات الوظيفية:
Flow .iterate( 0 )(_ + 1 ) // natural numbers
.filter(_ % 2 == 0 )
.map(_ + 1 )
.intersperse( 5 )
// compute the running total
.mapStateful(() => 0 ) { (state, value) =>
val newState = state + value
(newState, newState)
}
.take( 10 )
.runForeach(n => println(n.toString))
قم بإنشاء تدفقات تؤدي I/O وإدارة التزامن:
def sendHttpRequest ( entry : String ) : Unit = ???
Flow
.fromInputStream( this .getClass().getResourceAsStream( " /list.txt " ))
.linesUtf8
.mapPar( 4 )(sendHttpRequest)
.runDrain()
دمج تدفقان ، يتعاملان بشكل صحيح مع فشل أي فرعين:
val f1 = Flow .tick( 123 .millis, " left " )
val f2 = Flow .tick( 312 .millis, " right " )
f1.merge(f2).take( 100 ).runForeach(println)
دمج التدفق مع المكونات الأخرى باستخدام واجهة برمجة التطبيقات الضرورية:
def readNextBatch () : List [ String ] = ???
Flow .usingEmit { emit =>
forever :
readNextBatch().foreach(emit.apply)
}
استخدم قنوات عالية الأداء قابلة للكاملة للاتصال بين العمل داخل نطاقات التزامن:
val c = Channel .buffered[ String ]( 8 )
c.send( " Hello, " )
c.send( " World " )
c.done()
اختر من القنوات الشبيهة بالذهاب:
val c = Channel .rendezvous[ Int ]
val d = Channel .rendezvous[ Int ]
select(c.sendClause( 10 ), d.receiveClause)
unrap eithers وجمع الأخطاء في نوع الاتحاد:
val v1 : Either [ Int , String ] = ???
val v2 : Either [ Long , String ] = ???
val result : Either [ Int | Long , String ] = either :
v1.ok() ++ v2.ok()
قيم الأنابيب والنقر إلى وظائف لاستخدام Dot-Syntax:
def compute : Int = ???
def computeMore ( v : Int ) : Long = ???
compute
.pipe( 2 * _)
.tap(println)
.pipe(computeMore)
المزيد في المستندات!.
الهدف الأوسع المتمثل في Scala على الطراز المباشر هو تمكين الفرق من توصيل برامج العمل بسرعة وبثقة. تشمل مشاريعنا الأخرى ، بما في ذلك عميل STTP و Tapir ، أيضًا عمليات تكامل مصممة مباشرة نحو النمط المباشر.
علاوة على ذلك ، تحقق أيضًا من مشروع Gears ، وهي مكتبة تجريبية متعددة المنصات تغطي أيضًا Scala على الطراز المباشر.
ترحب جميع الاقتراحات :)
لتجميع واختبار ، قم بتشغيل:
sbt compile
sbt test
انظر قائمة القضايا واختيار واحدة! أو أبلغ عنك.
إذا كنت تشكك في السبب أو كيف يعمل شيء ما ، فلا تتردد في طرح سؤال حول الخطاب أو عبر Github. ربما يعني هذا أن الوثائق أو scaladocs أو الكود غير واضحة ويمكن تحسينها لصالح الجميع.
من أجل تطوير الوثائق ، يمكنك استخدام البرنامج النصي doc/watch.sh
، والذي يعمل على تشغيل sphinx باستخدام Python. استخدم doc/requirements.txt
لإعداد بيئة Python الخاصة بك مع pip
. بدلاً من ذلك ، إذا كنت من مستخدمي NIX ، فسيقوم بتطوير nix develop
في doc/
لبدء قذيفة مع بيئة تسمح بتشغيل watch.sh
. علاوة على ذلك ، يمكنك استخدام مهمة SBT compileDocumentation
للتحقق من أن جميع قصاصات الكود تجمع بشكل صحيح.
عندما يكون لديك PR جاهز ، ألق نظرة على دليل "كيفية إعداد PR". شكرًا! سائدا
نحن نقدم خدمات التنمية التجارية. اتصل بنا لمعرفة المزيد عنا!
حقوق الطبع والنشر (C) 2023-2024 Softwaremill https://softwaremill.com.