From 88656b6c97f8f9174e0c9e9b732bae4ceffbca8d Mon Sep 17 00:00:00 2001 From: Vladislav Podporkin Date: Mon, 14 Oct 2024 23:38:08 +0300 Subject: [PATCH] docs: Expand documentation structure --- docs/SUMMARY.md | 31 ++++- .../implementation-details.md} | 0 docs/ru/basics/creating/creating-comp-expr.md | 63 ++++++++++ .../creating-functions.md} | 109 +----------------- docs/ru/basics/creating/creating-manual.md | 12 ++ .../basics/creating/creating-of-async-task.md | 19 +++ docs/ru/basics/creating/creating.md | 1 + .../running-runtime.md} | 22 +--- docs/ru/basics/running/running-runtimeless.md | 15 +++ docs/ru/basics/running/running.md | 1 + 10 files changed, 143 insertions(+), 130 deletions(-) rename docs/ru/{ImplementationDetails.md => advanced/implementation-details.md} (100%) create mode 100644 docs/ru/basics/creating/creating-comp-expr.md rename docs/ru/basics/{creating.md => creating/creating-functions.md} (59%) create mode 100644 docs/ru/basics/creating/creating-manual.md create mode 100644 docs/ru/basics/creating/creating-of-async-task.md create mode 100644 docs/ru/basics/creating/creating.md rename docs/ru/basics/{running.md => running/running-runtime.md} (73%) create mode 100644 docs/ru/basics/running/running-runtimeless.md create mode 100644 docs/ru/basics/running/running.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index e897227..790b634 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -5,5 +5,32 @@ # Basics -- [Creating](ru/basics/creating.md) -- [Running](ru/basics/running.md) +- [Creating](ru/basics/creating/creating.md) + - [Functions](ru/basics/creating/creating-functions.md) + - [Computation Expressions](ru/basics/creating/creating-comp-expr.md) + - [From Async and Task](ru/basics/creating/creating-of-async-task.md) + - [Manual implementation](ru/basics/creating/creating-manual.md) + +- [Running](ru/basics/running/running.md) + - [Without runtime](ru/basics/running/running-runtimeless.md) + - [On runtime](ru/basics/running/running-runtime.md) + +- [Synchronisation]() + - ["Low-level" synchronisation primitives]() + - [Semaphore]() + - [Barrier]() + - [Mutex]() + - [RwLock]() + - [Notify]() + - [CondVar]() + - [OneShot]() + - ["High level" synchronisation primitives]() + - [OnceVar]() + - [LazyVar]() + - [MutexVar]() + - [RwLockVar]() + - [Mailbox]() + +# Advanced + +- [Implementation details](ru/advanced/implementation-details.md) diff --git a/docs/ru/ImplementationDetails.md b/docs/ru/advanced/implementation-details.md similarity index 100% rename from docs/ru/ImplementationDetails.md rename to docs/ru/advanced/implementation-details.md diff --git a/docs/ru/basics/creating/creating-comp-expr.md b/docs/ru/basics/creating/creating-comp-expr.md new file mode 100644 index 0000000..09847cc --- /dev/null +++ b/docs/ru/basics/creating/creating-comp-expr.md @@ -0,0 +1,63 @@ +# Создание Future используя Future CE + +Future имеет свой CE, который используется также как async или task CE встроенные в F#. +Более подробно о CE вы можете прочитать на [сайте](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions). + +Например, мы можем заменить базовые функции создания на future CE: +```fsharp +let ready = future { return "Hello, world!" } // ~ Future.ready "Hello, world!" +let lazy' = future { return (foo ()) } // ~ Future.lazy' (fun () -> foo ()) +``` + +Наиболее важным свойством CE является упрощение работы с bind. +Пример чтения-записи можно переписать используя CE так: + +```fsharp +// readFileAsync: filePath: string -> Future +// writeFileAsync: filePath: string -> content: string -> Future +let readAndWriteFuture = futur { + let! content = readFileAsync "my-file.txt" + return! writeFileAsync "other-file.txt" content +} +``` + +Видимым преимуществом CE является возможность "уплощить" цепочка bind, зависимых между собой. +Пример множественно зависимых bind можно переписать так: + +```fsharp +let doManyWorkWithCrossResults = future { + let! val1 = doWork1 () + let! val2 = doWork2 val1 + let! val3 = doWork3 val1 val2 + ... + let! valN = doWorkN val1 val2 ... valPrevN +} +``` + +Также CE добавляют синтаксис и для Future.merge или Future.catch комбинаторов. + +```fsharp +let parallelCE = future { + let! val1 = doWork1 () + and! val2 = doWork2 () + and! val3 = doWork3 () +} +``` + +```fsharp +let catchCE = future { + try + do! doWork () + with ex -> + printfn $"{ex}" +} +``` + +```fsharp +let tryFinally = future { + try + do! doWork () + finally + do finallize () +} +``` diff --git a/docs/ru/basics/creating.md b/docs/ru/basics/creating/creating-functions.md similarity index 59% rename from docs/ru/basics/creating.md rename to docs/ru/basics/creating/creating-functions.md index 32ad7de..b4f6d23 100644 --- a/docs/ru/basics/creating.md +++ b/docs/ru/basics/creating/creating-functions.md @@ -1,9 +1,4 @@ -# Создание объекта Future - -Создать асинхронное вычисление в лице Future можно большим количеством способов. - - -## Использование функций-комбинаторов +# Создание Future используя функции-комбинаторы Используя функции модуля Future можно создать базовые и получить скомбинированные вариации Future. Разберем базовые функции создания. @@ -74,7 +69,7 @@ let doManyWorkWithCrossResults = doWork2 val1 |> Future.bind (fun val2 -> doWork3 val1 val2 - |> Future.bind (fun val 3 -> ...))) + |> Future.bind (fun val3 -> ...))) ``` Future.bind позволяет соединять асинхронные вычисления в последовательную цепочку, @@ -116,103 +111,3 @@ let doubleFut = fut |> Future.bind (fun () -> fut) let doubleFut = someAsyncWork () |> Future.bind (fun () -> someAsyncWork ()) ``` - - -## Использование Future CE - -Future имеет свой CE, который используется также как async или task CE встроенные в F#. -Более подробно о CE вы можете прочитать на [сайте](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions). - -Например, мы можем заменить базовые функции создания на future CE: -```fsharp -let ready = future { return "Hello, world!" } // ~ Future.ready "Hello, world!" -let lazy' = future { return (foo ()) } // ~ Future.lazy' (fun () -> foo ()) -``` - -Наиболее важным свойством CE является упрощение работы с bind. -Пример чтения-записи можно переписать используя CE так: - -```fsharp -// readFileAsync: filePath: string -> Future -// writeFileAsync: filePath: string -> content: string -> Future -let readAndWriteFuture = futur { - let! content = readFileAsync "my-file.txt" - return! writeFileAsync "other-file.txt" content -} -``` - -Видимым преимуществом CE является возможность "уплощить" цепочка bind, зависимых между собой. -Пример множественно зависимых bind можно переписать так: - -```fsharp -let doManyWorkWithCrossResults = future { - let! val1 = doWork1 () - let! val2 = doWork2 val1 - let! val3 = doWork3 val1 val2 - ... - let! valN = doWorkN val1 val2 ... valPrevN -} -``` - -Также CE добавляют синтаксис и для Future.merge или Future.catch комбинаторов. - -```fsharp -let parallelCE = future { - let! val1 = doWork1 () - and! val2 = doWork2 () - and! val3 = doWork3 () -} -``` - -```fsharp -let catchCE = future { - try - do! doWork () - with ex -> - printfn $"{ex}" -} -``` - -```fsharp -let tryFinally = future { - try - do! doWork () - finally - do finallize () -} -``` - - -## Преобразование из Async и Task - -Существующие Async и Task можно преобразовать в Future и использовать результат их работы. -Исходные Async и Task будут запущены на своих родных системах запуска, но их результат будет -передан через возвращенную Future. - -```fsharp -let asyncToFuture = Future.ofAsync (async { ... }) -let taskToFuture = Future.ofTask (task { ... }) -``` - -Возможны и обратные преобразования. При этом Future будут запущены на механизме запуска -соответствующего примитива при запуске этого примитива. - -```fsharp -let futureToAsync = Future.ofAsync (async { ... }) -let futureToTask = Future.ofTask (task { ... }) -``` - - -## Ручная реализация Future - -Future это всего-лишь интерфейс с методами Poll и Drop. -Можно создать свою Future просто реализовав их. - -Ручная реализация Future корректным образом не такая тривиальная задача, -требующая ручной реализации конечного или не очень автомата. -Поэтому не рекомендуется делать это, только если Вы не разрабатываете -API для использования механизма асинхронности на низком уровне. - -Объяснения и более подробные примеры следует искать в более продвинутых главах. - - diff --git a/docs/ru/basics/creating/creating-manual.md b/docs/ru/basics/creating/creating-manual.md new file mode 100644 index 0000000..4cfe610 --- /dev/null +++ b/docs/ru/basics/creating/creating-manual.md @@ -0,0 +1,12 @@ +# Создание Future ручной реализацией Future + +Future это всего-лишь интерфейс с методами Poll и Drop. +Можно создать свою Future просто реализовав их. + +Ручная реализация Future корректным образом не такая тривиальная задача, +требующая ручной реализации конечного или не очень автомата. +Поэтому не рекомендуется делать это, только если Вы не разрабатываете +API для использования механизма асинхронности на низком уровне. + +Объяснения и более подробные примеры следует искать в более продвинутых главах. + diff --git a/docs/ru/basics/creating/creating-of-async-task.md b/docs/ru/basics/creating/creating-of-async-task.md new file mode 100644 index 0000000..8524cf4 --- /dev/null +++ b/docs/ru/basics/creating/creating-of-async-task.md @@ -0,0 +1,19 @@ +# Создание Future из Async и Task + +Существующие Async и Task можно преобразовать в Future и использовать результат их работы. +Исходные Async и Task будут запущены на своих родных системах запуска, но их результат будет +передан через возвращенную Future. + +```fsharp +let asyncToFuture = Future.ofAsync (async { ... }) +let taskToFuture = Future.ofTask (task { ... }) +``` + +Возможны и обратные преобразования. При этом Future будут запущены на механизме запуска +соответствующего примитива при запуске этого примитива. + +```fsharp +let futureToAsync = Future.ofAsync (async { ... }) +let futureToTask = Future.ofTask (task { ... }) +``` + diff --git a/docs/ru/basics/creating/creating.md b/docs/ru/basics/creating/creating.md new file mode 100644 index 0000000..6b32b74 --- /dev/null +++ b/docs/ru/basics/creating/creating.md @@ -0,0 +1 @@ +# Создание Future diff --git a/docs/ru/basics/running.md b/docs/ru/basics/running/running-runtime.md similarity index 73% rename from docs/ru/basics/running.md rename to docs/ru/basics/running/running-runtime.md index 7415843..ed4572e 100644 --- a/docs/ru/basics/running.md +++ b/docs/ru/basics/running/running-runtime.md @@ -1,24 +1,4 @@ -# Запуск Future - - -## Запуск на текущем потоке - -Future можно запустить на текущем потоке используя `Future.runBlocking`. -Переданная Future запустится, а вызывающий поток будет заблокирован -пока не получится результат. -```fsharp -let fut = future { - let! name = Future.ready "Alex" - do! Future.sleepMs 1000 - return $"Hello, {name}!" -} - -let phrase = fut |> Future.runBlocking -printfn $"{phrase}" -``` - - -## Запуск используя Runtime +# Запуск Future используя Runtime Future можно запустить на Runtime. Runtime это планировщик для нескольких параллельно выполняющихся Future, diff --git a/docs/ru/basics/running/running-runtimeless.md b/docs/ru/basics/running/running-runtimeless.md new file mode 100644 index 0000000..0a43daa --- /dev/null +++ b/docs/ru/basics/running/running-runtimeless.md @@ -0,0 +1,15 @@ +# Запуск Future без среды исполнения на текущем потоке + +Future можно запустить на текущем потоке используя `Future.runBlocking`. +Переданная Future запустится, а вызывающий поток будет заблокирован +пока не получится результат. +```fsharp +let fut = future { + let! name = Future.ready "Alex" + do! Future.sleepMs 1000 + return $"Hello, {name}!" +} + +let phrase = fut |> Future.runBlocking +printfn $"{phrase}" +``` diff --git a/docs/ru/basics/running/running.md b/docs/ru/basics/running/running.md new file mode 100644 index 0000000..9a97c3b --- /dev/null +++ b/docs/ru/basics/running/running.md @@ -0,0 +1 @@ +# Запуск Future