[{"data":1,"prerenderedAt":14526},["ShallowReactive",2],{"navigation_docs":3,"-python-asyncio":3379,"-python-asyncio-surround":14521},[4,1707,1912,2366,2547,2649,2856,2978,3028,3085,3119,3245,3322,3375],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1913,"icon":1914,"path":1915,"stem":1916,"children":1917,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1918,1944,1998,2020,2324,2362],{"title":1919,"icon":1920,"path":1921,"stem":1922,"children":1923,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1924,1928,1932,1936,1940],{"title":1925,"path":1926,"stem":1927},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1929,"path":1930,"stem":1931},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1933,"path":1934,"stem":1935},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1937,"path":1938,"stem":1939},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1941,"path":1942,"stem":1943},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1945,"icon":1946,"path":1947,"stem":1948,"children":1949,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1950,1954,1958,1962,1966,1970,1974,1978,1982,1986,1990,1994],{"title":1951,"path":1952,"stem":1953},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1955,"path":1956,"stem":1957},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1959,"path":1960,"stem":1961},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1963,"path":1964,"stem":1965},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1967,"path":1968,"stem":1969},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1971,"path":1972,"stem":1973},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1975,"path":1976,"stem":1977},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1979,"path":1980,"stem":1981},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1983,"path":1984,"stem":1985},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1987,"path":1988,"stem":1989},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1991,"path":1992,"stem":1993},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1995,"path":1996,"stem":1997},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1999,"icon":2000,"path":2001,"stem":2002,"children":2003,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2004,2008,2012,2016],{"title":2005,"path":2006,"stem":2007},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2009,"path":2010,"stem":2011},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2013,"path":2014,"stem":2015},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2017,"path":2018,"stem":2019},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2021,"icon":2022,"path":2023,"stem":2024,"children":2025},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2026,2027,2031,2035,2039,2043,2106,2141,2293],{"title":2021,"path":2023,"stem":2024},{"title":2028,"path":2029,"stem":2030},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2032,"path":2033,"stem":2034},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2036,"path":2037,"stem":2038},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2040,"path":2041,"stem":2042},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2044,"icon":132,"path":2045,"stem":2046,"children":2047},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2048,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094,2098,2102],{"title":2049,"path":2045,"stem":2046},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2051,"path":2052,"stem":2053},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2055,"path":2056,"stem":2057},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2059,"path":2060,"stem":2061},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2063,"path":2064,"stem":2065},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2067,"path":2068,"stem":2069},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2071,"path":2072,"stem":2073},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2075,"path":2076,"stem":2077},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2079,"path":2080,"stem":2081},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2083,"path":2084,"stem":2085},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2087,"path":2088,"stem":2089},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2091,"path":2092,"stem":2093},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2095,"path":2096,"stem":2097},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2099,"path":2100,"stem":2101},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2103,"path":2104,"stem":2105},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2107,"icon":2022,"path":2108,"stem":2109,"children":2110},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2111,2113,2117,2121,2125,2129,2133,2137],{"title":2112,"path":2108,"stem":2109},"React Router: Навігаційна система сучасного вебу",{"title":2114,"path":2115,"stem":2116},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2118,"path":2119,"stem":2120},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2122,"path":2123,"stem":2124},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2126,"path":2127,"stem":2128},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2130,"path":2131,"stem":2132},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2134,"path":2135,"stem":2136},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2138,"path":2139,"stem":2140},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2142,"icon":132,"path":2143,"stem":2144,"children":2145},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2146,2148,2164,2193,2202,2223,2239,2268],{"title":2147,"path":2143,"stem":2144},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2149,"stem":2150,"children":2151,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2152,2156,2160],{"title":2153,"path":2154,"stem":2155},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2157,"path":2158,"stem":2159},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2161,"path":2162,"stem":2163},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2165,"icon":132,"path":2166,"stem":2167,"children":2168,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2169,2173,2177,2181,2185,2189],{"title":2170,"path":2171,"stem":2172},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2174,"path":2175,"stem":2176},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2178,"path":2179,"stem":2180},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2182,"path":2183,"stem":2184},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2186,"path":2187,"stem":2188},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2190,"path":2191,"stem":2192},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2194,"icon":132,"path":2195,"stem":2196,"children":2197,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2198],{"title":2199,"path":2200,"stem":2201},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2203,"icon":132,"path":2204,"stem":2205,"children":2206,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2207,2211,2215,2219],{"title":2208,"path":2209,"stem":2210},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2212,"path":2213,"stem":2214},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2216,"path":2217,"stem":2218},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2220,"path":2221,"stem":2222},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2224,"icon":92,"path":2225,"stem":2226,"children":2227,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2228,2232,2236],{"title":2229,"path":2230,"stem":2231},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2233,"path":2234,"stem":2235},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2083,"path":2237,"stem":2238},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2240,"icon":132,"path":2241,"stem":2242,"children":2243,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2244,2248,2252,2256,2260,2264],{"title":2245,"path":2246,"stem":2247},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2249,"path":2250,"stem":2251},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2253,"path":2254,"stem":2255},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2257,"path":2258,"stem":2259},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2261,"path":2262,"stem":2263},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2265,"path":2266,"stem":2267},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2269,"icon":132,"path":2270,"stem":2271,"children":2272,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2273,2277,2281,2285,2289],{"title":2274,"path":2275,"stem":2276},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2278,"path":2279,"stem":2280},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2282,"path":2283,"stem":2284},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2286,"path":2287,"stem":2288},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2290,"path":2291,"stem":2292},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2294,"icon":132,"path":2295,"stem":2296,"children":2297},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2298,2300,2304,2308,2312,2316,2320],{"title":2299,"path":2295,"stem":2296},"UI Бібліотеки в React",{"title":2301,"path":2302,"stem":2303},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2305,"path":2306,"stem":2307},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2309,"path":2310,"stem":2311},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2313,"path":2314,"stem":2315},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2317,"path":2318,"stem":2319},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2321,"path":2322,"stem":2323},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2325,"icon":2326,"path":2327,"stem":2328,"children":2329,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2330,2334,2338,2342,2346,2350,2354,2358],{"title":2331,"path":2332,"stem":2333},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2335,"path":2336,"stem":2337},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2339,"path":2340,"stem":2341},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2343,"path":2344,"stem":2345},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2347,"path":2348,"stem":2349},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2351,"path":2352,"stem":2353},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2355,"path":2356,"stem":2357},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2359,"path":2360,"stem":2361},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2363,"path":2364,"stem":2365},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2367,"icon":2368,"path":2369,"stem":2370,"children":2371,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2372,2375,2378,2382,2386,2390,2394],{"title":162,"path":2373,"stem":2374},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2376,"stem":2377},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2379,"path":2380,"stem":2381},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2383,"path":2384,"stem":2385},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2387,"path":2388,"stem":2389},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2391,"path":2392,"stem":2393},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2395,"path":2396,"stem":2397,"children":2398,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535,2539,2543],{"title":2400,"path":2401,"stem":2402},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2404,"path":2405,"stem":2406},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2408,"path":2409,"stem":2410},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2412,"path":2413,"stem":2414},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2416,"path":2417,"stem":2418},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2420,"path":2421,"stem":2422},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2424,"path":2425,"stem":2426},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2428,"path":2429,"stem":2430},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2432,"path":2433,"stem":2434},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2436,"path":2437,"stem":2438},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2440,"path":2441,"stem":2442},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2444,"path":2445,"stem":2446},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2448,"path":2449,"stem":2450},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2452,"path":2453,"stem":2454},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2456,"path":2457,"stem":2458},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2460,"path":2461,"stem":2462},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2464,"path":2465,"stem":2466},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2468,"path":2469,"stem":2470},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2472,"path":2473,"stem":2474},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2476,"path":2477,"stem":2478},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2480,"path":2481,"stem":2482},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2484,"path":2485,"stem":2486},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2488,"path":2489,"stem":2490},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2492,"path":2493,"stem":2494},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2496,"path":2497,"stem":2498},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2500,"path":2501,"stem":2502},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2504,"path":2505,"stem":2506},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2508,"path":2509,"stem":2510},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2512,"path":2513,"stem":2514},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2516,"path":2517,"stem":2518},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2520,"path":2521,"stem":2522},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2524,"path":2525,"stem":2526},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2528,"path":2529,"stem":2530},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2532,"path":2533,"stem":2534},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2536,"path":2537,"stem":2538},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2540,"path":2541,"stem":2542},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2544,"path":2545,"stem":2546},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2548,"icon":2549,"path":2550,"stem":2551,"children":2552,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2553,2557,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604,2608,2645],{"title":2554,"path":2555,"stem":2556},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2558,"stem":2559},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2561,"path":2562,"stem":2563},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2565,"path":2566,"stem":2567},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2569,"path":2570,"stem":2571},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2573,"path":2574,"stem":2575},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2577,"path":2578,"stem":2579},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2581,"path":2582,"stem":2583},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2585,"path":2586,"stem":2587},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2589,"path":2590,"stem":2591},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2593,"path":2594,"stem":2595},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2597,"path":2598,"stem":2599},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2601,"path":2602,"stem":2603},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2605,"path":2606,"stem":2607},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2609,"icon":92,"path":2610,"stem":2611,"children":2612,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2613,2617,2621,2625,2629,2633,2637,2641],{"title":2614,"path":2615,"stem":2616},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2618,"path":2619,"stem":2620},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2622,"path":2623,"stem":2624},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2626,"path":2627,"stem":2628},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2630,"path":2631,"stem":2632},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2634,"path":2635,"stem":2636},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2638,"path":2639,"stem":2640},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2642,"path":2643,"stem":2644},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2646,"path":2647,"stem":2648},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2650,"icon":2651,"path":2652,"stem":2653,"children":2654,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2655,2685,2708,2745,2774,2792,2826,2838,2847],{"title":2656,"icon":2657,"path":2658,"stem":2659,"children":2660,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2661,2665,2669,2673,2677,2681],{"title":2662,"path":2663,"stem":2664},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2666,"path":2667,"stem":2668},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2670,"path":2671,"stem":2672},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2674,"path":2675,"stem":2676},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2678,"path":2679,"stem":2680},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2682,"path":2683,"stem":2684},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2686,"icon":2651,"path":2687,"stem":2688,"children":2689,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2690,2694,2700,2704],{"title":2691,"path":2692,"stem":2693},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2695,"path":2696,"stem":2697,"children":2698},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2699],{"title":2695,"path":2696,"stem":2697},{"title":2701,"path":2702,"stem":2703},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2705,"path":2706,"stem":2707},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2709,"icon":2651,"path":2710,"stem":2711,"children":2712,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2713,2717,2721,2725,2729,2733,2737,2741],{"title":2714,"path":2715,"stem":2716},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2718,"path":2719,"stem":2720},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2722,"path":2723,"stem":2724},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2726,"path":2727,"stem":2728},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2730,"path":2731,"stem":2732},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2734,"path":2735,"stem":2736},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2738,"path":2739,"stem":2740},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2742,"path":2743,"stem":2744},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2746,"icon":2651,"path":2747,"stem":2748,"children":2749,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2750,2754,2758,2762,2766,2770],{"title":2751,"path":2752,"stem":2753},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2755,"path":2756,"stem":2757},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2759,"path":2760,"stem":2761},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2763,"path":2764,"stem":2765},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2767,"path":2768,"stem":2769},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2771,"path":2772,"stem":2773},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2775,"icon":2776,"path":2777,"stem":2778,"children":2779,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2780,2784,2788],{"title":2781,"path":2782,"stem":2783},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2785,"path":2786,"stem":2787},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2789,"path":2790,"stem":2791},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2793,"icon":2794,"path":2795,"stem":2796,"children":2797,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2798,2802,2806,2810,2814,2818,2822],{"title":2799,"path":2800,"stem":2801},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2803,"path":2804,"stem":2805},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2807,"path":2808,"stem":2809},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2811,"path":2812,"stem":2813},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2815,"path":2816,"stem":2817},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2819,"path":2820,"stem":2821},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2823,"path":2824,"stem":2825},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2823,"icon":793,"path":2827,"stem":2828,"children":2829,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2830,2834],{"title":2831,"path":2832,"stem":2833},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2835,"path":2836,"stem":2837},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2839,"icon":2840,"path":2841,"stem":2842,"children":2843,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2844],{"title":2839,"path":2845,"stem":2846},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2848,"icon":2849,"path":2850,"stem":2851,"children":2852,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2853],{"title":2848,"path":2854,"stem":2855},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2857,"icon":2858,"path":2859,"stem":2860,"children":2861,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2862,2938],{"title":2863,"icon":2864,"path":2865,"stem":2866,"children":2867},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2868,2870,2874,2878,2882,2886,2890,2894,2898,2902,2906,2910,2914,2918,2922,2926,2930,2934],{"title":2869,"path":2865,"stem":2866},"Docker: від нуля до production",{"title":2871,"path":2872,"stem":2873},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2875,"path":2876,"stem":2877},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2879,"path":2880,"stem":2881},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2883,"path":2884,"stem":2885},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2887,"path":2888,"stem":2889},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2891,"path":2892,"stem":2893},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2895,"path":2896,"stem":2897},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2899,"path":2900,"stem":2901},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2903,"path":2904,"stem":2905},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2907,"path":2908,"stem":2909},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2911,"path":2912,"stem":2913},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2915,"path":2916,"stem":2917},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2919,"path":2920,"stem":2921},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2923,"path":2924,"stem":2925},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2927,"path":2928,"stem":2929},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2931,"path":2932,"stem":2933},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2935,"path":2936,"stem":2937},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2939,"icon":2940,"path":2941,"stem":2942,"children":2943},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2944,2946,2950,2954,2958,2962,2966,2970,2974],{"title":2945,"path":2941,"stem":2942},"Kubernetes: від розробки до production",{"title":2947,"path":2948,"stem":2949},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2951,"path":2952,"stem":2953},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2955,"path":2956,"stem":2957},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2959,"path":2960,"stem":2961},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2963,"path":2964,"stem":2965},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2967,"path":2968,"stem":2969},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2971,"path":2972,"stem":2973},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2975,"path":2976,"stem":2977},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":2979,"icon":2980,"path":2981,"stem":2982,"children":2983,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[2984,2988,2992,2996,3000,3004,3008,3012,3016,3020,3024],{"title":2985,"path":2986,"stem":2987},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":2989,"path":2990,"stem":2991},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":2993,"path":2994,"stem":2995},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":2997,"path":2998,"stem":2999},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3001,"path":3002,"stem":3003},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3005,"path":3006,"stem":3007},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3009,"path":3010,"stem":3011},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3013,"path":3014,"stem":3015},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3017,"path":3018,"stem":3019},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3021,"path":3022,"stem":3023},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3025,"path":3026,"stem":3027},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3029,"icon":943,"path":3030,"stem":3031,"children":3032,"page":59},"DDD","\u002Fddd","10.ddd",[3033,3037,3041,3045,3049,3053,3057,3061,3065,3069,3073,3077,3081],{"title":3034,"path":3035,"stem":3036},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3038,"path":3039,"stem":3040},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3042,"path":3043,"stem":3044},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3046,"path":3047,"stem":3048},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3050,"path":3051,"stem":3052},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3054,"path":3055,"stem":3056},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3058,"path":3059,"stem":3060},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3062,"path":3063,"stem":3064},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3066,"path":3067,"stem":3068},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3070,"path":3071,"stem":3072},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3074,"path":3075,"stem":3076},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3078,"path":3079,"stem":3080},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3082,"path":3083,"stem":3084},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3086,"icon":3087,"path":3088,"stem":3089,"children":3090,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3091,3095,3099,3103,3107,3111,3115],{"title":3092,"path":3093,"stem":3094},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3096,"path":3097,"stem":3098},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3100,"path":3101,"stem":3102},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3104,"path":3105,"stem":3106},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3108,"path":3109,"stem":3110},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3112,"path":3113,"stem":3114},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3116,"path":3117,"stem":3118},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3120,"icon":3121,"path":3122,"stem":3123,"children":3124,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3125,3129,3133,3137,3141,3145,3149,3153,3157,3161,3165,3169,3173,3177,3181,3185,3189,3193,3197,3201,3205,3209,3213,3217,3221,3225,3229,3233,3237,3241],{"title":3126,"path":3127,"stem":3128},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3130,"path":3131,"stem":3132},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3134,"path":3135,"stem":3136},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3138,"path":3139,"stem":3140},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3142,"path":3143,"stem":3144},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3146,"path":3147,"stem":3148},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3150,"path":3151,"stem":3152},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3154,"path":3155,"stem":3156},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3158,"path":3159,"stem":3160},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3162,"path":3163,"stem":3164},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3166,"path":3167,"stem":3168},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3170,"path":3171,"stem":3172},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3174,"path":3175,"stem":3176},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3178,"path":3179,"stem":3180},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3182,"path":3183,"stem":3184},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3186,"path":3187,"stem":3188},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3190,"path":3191,"stem":3192},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3194,"path":3195,"stem":3196},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3198,"path":3199,"stem":3200},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3202,"path":3203,"stem":3204},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3206,"path":3207,"stem":3208},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3210,"path":3211,"stem":3212},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3214,"path":3215,"stem":3216},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3218,"path":3219,"stem":3220},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3222,"path":3223,"stem":3224},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3226,"path":3227,"stem":3228},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3230,"path":3231,"stem":3232},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3234,"path":3235,"stem":3236},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3238,"path":3239,"stem":3240},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3242,"path":3243,"stem":3244},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3246,"path":3247,"stem":3248,"children":3249,"page":59},"AWS","\u002Faws","13.aws",[3250,3254,3258,3262,3266,3270,3274,3278,3282,3286,3290,3294,3298,3302,3306,3310,3314,3318],{"title":3251,"path":3252,"stem":3253},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3255,"path":3256,"stem":3257},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3259,"path":3260,"stem":3261},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3263,"path":3264,"stem":3265},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3267,"path":3268,"stem":3269},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3271,"path":3272,"stem":3273},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3275,"path":3276,"stem":3277},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3279,"path":3280,"stem":3281},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3283,"path":3284,"stem":3285},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3287,"path":3288,"stem":3289},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3291,"path":3292,"stem":3293},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3295,"path":3296,"stem":3297},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3299,"path":3300,"stem":3301},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3303,"path":3304,"stem":3305},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3307,"path":3308,"stem":3309},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3311,"path":3312,"stem":3313},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3315,"path":3316,"stem":3317},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3319,"path":3320,"stem":3321},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3323,"path":3324,"stem":3325,"children":3326,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3327,3331,3335,3339,3343,3347,3351,3355,3359,3363,3367,3371],{"title":3328,"path":3329,"stem":3330},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3332,"path":3333,"stem":3334},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3336,"path":3337,"stem":3338},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3340,"path":3341,"stem":3342},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3344,"path":3345,"stem":3346},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3348,"path":3349,"stem":3350},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3352,"path":3353,"stem":3354},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3356,"path":3357,"stem":3358},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3360,"path":3361,"stem":3362},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3364,"path":3365,"stem":3366},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3368,"path":3369,"stem":3370},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3372,"path":3373,"stem":3374},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3376,"path":3377,"stem":3378},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3380,"title":2605,"body":3381,"description":14515,"extension":14516,"links":14517,"meta":14518,"navigation":3597,"path":2606,"seo":14519,"stem":2607,"__hash__":14520},"docs\u002F05.python\u002F14.asyncio.md",{"type":3382,"value":3383,"toc":14449},"minimark",[3384,3388,3393,3402,3405,3408,3412,3415,3418,3421,3442,3457,3460,3465,3468,3508,3510,3514,3518,3521,3557,3563,3731,3734,3736,3740,3746,3929,3935,3962,3978,3981,4194,4230,4253,4260,4266,4271,4280,4416,4419,4672,4679,4689,4696,5028,5075,5094,5096,5105,5113,5115,5119,5137,5148,5154,5397,5435,5437,5441,5449,5455,5584,5588,5604,5860,5862,5869,5882,5888,5923,5926,6177,6179,6186,6192,6313,6320,6326,6384,6412,6414,6424,6438,6440,6446,6458,6462,6490,6514,6518,6556,6880,6919,6921,6927,6932,6935,6955,6984,7451,7459,7461,7468,7489,7492,7517,7569,8044,8046,8053,8061,8064,8082,8105,8302,8304,8310,8326,8333,8367,8638,8648,8650,8654,8665,8667,8674,8680,8684,8707,8717,8993,8995,9002,9016,9020,9038,9046,9049,9452,9454,9461,9468,9471,9507,9834,9836,9843,9853,9856,9875,9888,9892,9938,10386,10388,10398,10404,10411,10421,10428,10434,10442,10453,10885,10894,10896,10900,10916,10925,10927,10934,10945,10949,10958,10989,10993,11017,11509,11528,11530,11534,11537,11541,11544,11709,11715,11721,11876,11883,11889,12059,12066,12069,12161,12165,12174,12281,12283,12287,12301,13812,13910,13912,13916,13920,14200,14204,14355,14361,14445],[3385,3386,2605],"h1",{"id":3387},"asyncio-кооперативна-конкурентність-та-event-loop",[3389,3390,3392],"h2",{"id":3391},"проблема-c10k-10-000-зєднань-один-сервер","Проблема C10K: 10 000 з'єднань, один сервер",[3394,3395,3396,3397,3401],"p",{},"Під час проєктування сучасних мережевих систем (наприклад, чат-серверів, WebSocket-шлюзів або API-серверів реального часу) розробники стикаються з проблемою ",[3398,3399,3400],"strong",{},"C10K (Concurrent 10,000 Connections)"," — потребою обслуговувати 10 000 і більше одночасних клієнтських з'єднань на одному фізичному сервері.",[3394,3403,3404],{},"У класичній синхронній моделі програмування кожне нове мережеве з'єднання обслуговується окремим потоком операційної системи (Thread-per-Connection). Проте потоки ОС мають високу ціну.",[3394,3406,3407],{},"Обчислимо приблизний обсяг ресурсів для такої моделі за формулою:",[3409,3410,3411],"math-formula",{},"Memory* = N \\times Stack* + ContextSwitch_{overhead}",[3394,3413,3414],{},"Якщо підставити реальні значення для 10 000 активних потоків, де розмір стеку одного потоку в Linux\u002FUnix системах зазвичай становить 512 КБ:",[3409,3416,3417],{},"10,000 \\times 512 \\text{ KB} \\approx 5 \\text{ GB}",[3394,3419,3420],{},"Окрім споживання 5 ГБ оперативної пам'яті виключно на службові стеки потоків, виникають інші обмеження:",[3422,3423,3424,3431],"ol",{},[3425,3426,3427,3430],"li",{},[3398,3428,3429],{},"Переключення контексту (Context Switching)",": Ядро операційної системи витрачає значну частину процесорного часу на перемикання між тисячами потоків (збереження регістрів CPU, таблиць сторінок пам'яті тощо), замість виконання корисної роботи.",[3425,3432,3433,3436,3437,3441],{},[3398,3434,3435],{},"Системні ліміти",": В ОС Linux за замовчуванням встановлені жорсткі ліміти на загальну кількість потоків (наприклад, ",[3438,3439,3440],"code",{},"\u002Fproc\u002Fsys\u002Fkernel\u002Fthreads-max"," зазвичай обмежує їх до ~32 000).",[3394,3443,3444,3445,3448,3449,3452,3453,3456],{},"Система почне деградувати задовго до досягнення 10 000 з'єднань. Щоб вирішити цю проблему, у 2002 році при розробці вебсервера Nginx було запропоновано подієво-орієнтований підхід (Event-Driven) на основі ",[3398,3446,3447],{},"Event Loop (циклу подій)",". У Python офіційна підтримка цієї моделі з'явилася у вигляді бібліотеки ",[3438,3450,3451],{},"asyncio"," (PEP 3156, Python 3.4, яка отримала нативний синтаксис ",[3438,3454,3455],{},"async\u002Fawait"," у Python 3.5 та була кардинально покращена в 3.7+).",[3458,3459],"hr",{},[3461,3462,3464],"h3",{"id":3463},"порівняння-парадигм-конкурентності","Порівняння парадигм конкурентності",[3394,3466,3467],{},"Для кращого розуміння відмінностей між потоками та асинхронністю, порівняємо їх ключові характеристики:",[3469,3470,3471,3477,3490,3495],"card-group",{},[3472,3473,3476],"card",{"icon":3474,"title":3475},"i-heroicons-cpu-chip","Потоки: preemptive (витісняюча)","Операційна система примусово призупиняє роботу одного потоку та перемикає CPU на інший за таймером (квантування часу). Це вимагає складних блокувань (Locks, Mutexes) для уникнення Race Conditions. Кожен потік потребує окремого стеку пам'яті.",[3472,3478,3481,3482,3485,3486,3489],{"icon":3479,"title":3480},"i-heroicons-arrow-path","asyncio: cooperative (кооперативна)","Корутини виконуються на ",[3398,3483,3484],{},"одному потоці",". Перемикання контексту відбувається добровільно лише у строго визначених точках — біля ключового слова ",[3438,3487,3488],{},"await",". Відсутні примусові переривання CPU, а споживання пам'яті на корутину вимірюється байтами.",[3472,3491,3494],{"icon":3492,"title":3493},"i-heroicons-bolt","Де asyncio є ідеальним","Будь-які операції I\u002FO-bound (введення-виведення): мережеві HTTP-запити, вебсокети, взаємодія з базами даних, робота з чергами повідомлень (RabbitMQ, Redis), парсинг сайтів або дискове I\u002FO.",[3472,3496,3499,3500,3503,3504,3507],{"icon":3497,"title":3498},"i-heroicons-x-circle","Де asyncio не допоможе","CPU-bound задачі (складні математичні обчислення, обробка зображень, кодування відео). Оскільки event loop працює в одному потоці, CPU-bound завдання повністю заблокує його. Для них слід використовувати ",[3438,3501,3502],{},"multiprocessing"," або фонові пули через ",[3438,3505,3506],{},"run_in_executor",".",[3458,3509],{},[3389,3511,3513],{"id":3512},"частина-i-модель-event-loop-як-це-працює-зсередини","Частина I: Модель event loop — як це працює зсередини",[3461,3515,3517],{"id":3516},"від-callbacks-до-coroutines-еволюція-асинхронного-python","Від callbacks до coroutines: еволюція асинхронного Python",[3394,3519,3520],{},"Історично асинхронне програмування в Python розвивалося у три етапи:",[3422,3522,3523,3532,3545],{},[3425,3524,3525,3528,3529,3531],{},[3398,3526,3527],{},"Callback-style (Покоління 1)",": Асинхронність на основі зворотних викликів. Функція ініціює операцію та передає іншу функцію (callback), яку треба викликати після завершення. Цей підхід використовувався у старих фреймворках (Twisted, Tornado) та низькорівневих протоколах ",[3438,3530,3451],{},". Наслідком є \"Callback Hell\" (велика вкладеність коду).",[3425,3533,3534,3537,3538,3541,3542,3507],{},[3398,3535,3536],{},"Generators & yield from (Покоління 2)",": З появою PEP 380 (Python 3.3) генератори отримали конструкцію ",[3438,3539,3540],{},"yield from",". Це дозволило писати асинхронний код, який виглядав лінійно, але функції доводилося декорувати як ",[3438,3543,3544],{},"@asyncio.coroutine",[3425,3546,3547,3550,3551,3554,3555,3507],{},[3398,3548,3549],{},"Native Coroutines (Покоління 3)",": Починаючи з PEP 492 (Python 3.5), мова отримала першокласну підтримку корутин через ключові слова ",[3438,3552,3553],{},"async def"," та ",[3438,3556,3488],{},[3394,3558,3559,3560,3562],{},"Поглянемо на старий низькорівневий callback-стиль, який досі використовується під капотом ",[3438,3561,3451],{}," для взаємодії з мережевими сокетами:",[3564,3565,3570],"pre",{"className":3566,"code":3567,"language":3568,"meta":3569,"style":3569},"language-python shiki shiki-themes light-plus dark-plus dark-plus","# callback_style.py — низькорівнева callback-модель\nimport asyncio\n\ndef on_data_received(data: bytes) -> None:\n    \"\"\"Викликається автоматично при надходженні даних у сокет.\"\"\"\n    print(f\"Отримано: {data.decode()}\")\n\ndef on_connection_made(transport) -> None:\n    \"\"\"Викликається при успішному встановленні з'єднання.\"\"\"\n    transport.write(b\"Hello!\\n\")\n    # Передаємо callback для обробки вхідних даних\n    # transport.register_reader(on_data_received)\n","python","",[3438,3571,3572,3581,3592,3599,3633,3640,3669,3674,3693,3699,3719,3725],{"__ignoreMap":3569},[3573,3574,3577],"span",{"class":3575,"line":3576},"line",1,[3573,3578,3580],{"class":3579},"spJ8K","# callback_style.py — низькорівнева callback-модель\n",[3573,3582,3584,3588],{"class":3575,"line":3583},2,[3573,3585,3587],{"class":3586},"s8xlr","import",[3573,3589,3591],{"class":3590},"sHH4Y"," asyncio\n",[3573,3593,3595],{"class":3575,"line":3594},3,[3573,3596,3598],{"emptyLinePlaceholder":3597},true,"\n",[3573,3600,3602,3606,3610,3613,3617,3620,3624,3627,3630],{"class":3575,"line":3601},4,[3573,3603,3605],{"class":3604},"su1O8","def",[3573,3607,3609],{"class":3608},"s8Opu"," on_data_received",[3573,3611,3612],{"class":3590},"(",[3573,3614,3616],{"class":3615},"siwwj","data",[3573,3618,3619],{"class":3590},": ",[3573,3621,3623],{"class":3622},"sN1BT","bytes",[3573,3625,3626],{"class":3590},") -> ",[3573,3628,3629],{"class":3604},"None",[3573,3631,3632],{"class":3590},":\n",[3573,3634,3636],{"class":3575,"line":3635},5,[3573,3637,3639],{"class":3638},"sbdoH","    \"\"\"Викликається автоматично при надходженні даних у сокет.\"\"\"\n",[3573,3641,3643,3646,3648,3651,3654,3657,3660,3663,3666],{"class":3575,"line":3642},6,[3573,3644,3645],{"class":3608},"    print",[3573,3647,3612],{"class":3590},[3573,3649,3650],{"class":3604},"f",[3573,3652,3653],{"class":3638},"\"Отримано: ",[3573,3655,3656],{"class":3604},"{",[3573,3658,3659],{"class":3590},"data.decode()",[3573,3661,3662],{"class":3604},"}",[3573,3664,3665],{"class":3638},"\"",[3573,3667,3668],{"class":3590},")\n",[3573,3670,3672],{"class":3575,"line":3671},7,[3573,3673,3598],{"emptyLinePlaceholder":3597},[3573,3675,3677,3679,3682,3684,3687,3689,3691],{"class":3575,"line":3676},8,[3573,3678,3605],{"class":3604},[3573,3680,3681],{"class":3608}," on_connection_made",[3573,3683,3612],{"class":3590},[3573,3685,3686],{"class":3615},"transport",[3573,3688,3626],{"class":3590},[3573,3690,3629],{"class":3604},[3573,3692,3632],{"class":3590},[3573,3694,3696],{"class":3575,"line":3695},9,[3573,3697,3698],{"class":3638},"    \"\"\"Викликається при успішному встановленні з'єднання.\"\"\"\n",[3573,3700,3702,3705,3708,3711,3715,3717],{"class":3575,"line":3701},10,[3573,3703,3704],{"class":3590},"    transport.write(",[3573,3706,3707],{"class":3604},"b",[3573,3709,3710],{"class":3638},"\"Hello!",[3573,3712,3714],{"class":3713},"sjcCO","\\n",[3573,3716,3665],{"class":3638},[3573,3718,3668],{"class":3590},[3573,3720,3722],{"class":3575,"line":3721},11,[3573,3723,3724],{"class":3579},"    # Передаємо callback для обробки вхідних даних\n",[3573,3726,3728],{"class":3575,"line":3727},12,[3573,3729,3730],{"class":3579},"    # transport.register_reader(on_data_received)\n",[3394,3732,3733],{},"Асинхронний код на базі корутин повністю приховує цю низькорівневу рутину, надаючи розробнику лінійний імперативний інтерфейс.",[3458,3735],{},[3461,3737,3739],{"id":3738},"анатомія-event-loop","Анатомія Event Loop",[3394,3741,3742,3745],{},[3398,3743,3744],{},"Event Loop (цикл подій)"," — це ядро асинхронної архітектури. З концептуальної точки зору це нескінченний цикл, який керує чергою подій та координує виконання корутин:",[3747,3748,3749],"plant-uml",{},[3564,3750,3754],{"className":3751,"code":3752,"language":3753,"meta":3569,"style":3569},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam linetype ortho\n\ntitle Цикл обробки подій (Event Loop)\n\nstart\nrepeat\n  :1. Опитування ОС (Multiplexing: epoll \u002F kqueue \u002F IOCP);\n  note right\n    Блокуючий запит до ядра ОС з таймаутом\n    для виявлення готових файлових дескрипторів сокетів\n  end note\n\n  :2. Виявлено завершені I\u002FO події?;\n  if (Так) then (yes)\n    :Додати відповідні Callbacks у чергу готових завдань;\n  endif\n\n  :3. Виконання черги готових завдань (Ready Queue);\n  while (Черга не порожня?) is (Так)\n    :Вилучити наступне завдання (Task\u002FCallback);\n    :Виконати черговий крок (step) корутини до наступного await;\n  endwhile (Ні)\n\n  :4. Обробка запланованих за часом подій (Scheduled Tasks);\n  note right\n    Виконання завдань типу asyncio.sleep()\n  end note\nrepeat while (Loop працює?)\nstop\n@enduml\n","plantuml",[3438,3755,3756,3761,3766,3771,3775,3780,3784,3789,3794,3799,3804,3809,3814,3820,3825,3831,3837,3843,3849,3854,3860,3866,3872,3878,3884,3889,3895,3900,3906,3911,3917,3923],{"__ignoreMap":3569},[3573,3757,3758],{"class":3575,"line":3576},[3573,3759,3760],{},"@startuml\n",[3573,3762,3763],{"class":3575,"line":3583},[3573,3764,3765],{},"skinparam style plain\n",[3573,3767,3768],{"class":3575,"line":3594},[3573,3769,3770],{},"skinparam linetype ortho\n",[3573,3772,3773],{"class":3575,"line":3601},[3573,3774,3598],{"emptyLinePlaceholder":3597},[3573,3776,3777],{"class":3575,"line":3635},[3573,3778,3779],{},"title Цикл обробки подій (Event Loop)\n",[3573,3781,3782],{"class":3575,"line":3642},[3573,3783,3598],{"emptyLinePlaceholder":3597},[3573,3785,3786],{"class":3575,"line":3671},[3573,3787,3788],{},"start\n",[3573,3790,3791],{"class":3575,"line":3676},[3573,3792,3793],{},"repeat\n",[3573,3795,3796],{"class":3575,"line":3695},[3573,3797,3798],{},"  :1. Опитування ОС (Multiplexing: epoll \u002F kqueue \u002F IOCP);\n",[3573,3800,3801],{"class":3575,"line":3701},[3573,3802,3803],{},"  note right\n",[3573,3805,3806],{"class":3575,"line":3721},[3573,3807,3808],{},"    Блокуючий запит до ядра ОС з таймаутом\n",[3573,3810,3811],{"class":3575,"line":3727},[3573,3812,3813],{},"    для виявлення готових файлових дескрипторів сокетів\n",[3573,3815,3817],{"class":3575,"line":3816},13,[3573,3818,3819],{},"  end note\n",[3573,3821,3823],{"class":3575,"line":3822},14,[3573,3824,3598],{"emptyLinePlaceholder":3597},[3573,3826,3828],{"class":3575,"line":3827},15,[3573,3829,3830],{},"  :2. Виявлено завершені I\u002FO події?;\n",[3573,3832,3834],{"class":3575,"line":3833},16,[3573,3835,3836],{},"  if (Так) then (yes)\n",[3573,3838,3840],{"class":3575,"line":3839},17,[3573,3841,3842],{},"    :Додати відповідні Callbacks у чергу готових завдань;\n",[3573,3844,3846],{"class":3575,"line":3845},18,[3573,3847,3848],{},"  endif\n",[3573,3850,3852],{"class":3575,"line":3851},19,[3573,3853,3598],{"emptyLinePlaceholder":3597},[3573,3855,3857],{"class":3575,"line":3856},20,[3573,3858,3859],{},"  :3. Виконання черги готових завдань (Ready Queue);\n",[3573,3861,3863],{"class":3575,"line":3862},21,[3573,3864,3865],{},"  while (Черга не порожня?) is (Так)\n",[3573,3867,3869],{"class":3575,"line":3868},22,[3573,3870,3871],{},"    :Вилучити наступне завдання (Task\u002FCallback);\n",[3573,3873,3875],{"class":3575,"line":3874},23,[3573,3876,3877],{},"    :Виконати черговий крок (step) корутини до наступного await;\n",[3573,3879,3881],{"class":3575,"line":3880},24,[3573,3882,3883],{},"  endwhile (Ні)\n",[3573,3885,3887],{"class":3575,"line":3886},25,[3573,3888,3598],{"emptyLinePlaceholder":3597},[3573,3890,3892],{"class":3575,"line":3891},26,[3573,3893,3894],{},"  :4. Обробка запланованих за часом подій (Scheduled Tasks);\n",[3573,3896,3898],{"class":3575,"line":3897},27,[3573,3899,3803],{},[3573,3901,3903],{"class":3575,"line":3902},28,[3573,3904,3905],{},"    Виконання завдань типу asyncio.sleep()\n",[3573,3907,3909],{"class":3575,"line":3908},29,[3573,3910,3819],{},[3573,3912,3914],{"class":3575,"line":3913},30,[3573,3915,3916],{},"repeat while (Loop працює?)\n",[3573,3918,3920],{"class":3575,"line":3919},31,[3573,3921,3922],{},"stop\n",[3573,3924,3926],{"class":3575,"line":3925},32,[3573,3927,3928],{},"@enduml\n",[3394,3930,3931,3932,3934],{},"Під капотом ",[3438,3933,3451],{}," використовує системні виклики операційної системи для мультиплексування введення-виведення:",[3936,3937,3938,3946,3954],"ul",{},[3425,3939,3940,3945],{},[3398,3941,3942],{},[3438,3943,3944],{},"epoll"," — у сімействі Linux.",[3425,3947,3948,3953],{},[3398,3949,3950],{},[3438,3951,3952],{},"kqueue"," — у macOS та BSD-системах.",[3425,3955,3956,3961],{},[3398,3957,3958],{},[3438,3959,3960],{},"IOCP (Input\u002FOutput Completion Ports)"," — у Windows.",[3394,3963,3964,3965,3970,3971,3974,3975,3977],{},"Для досягнення максимальної продуктивності в продакшені стандартний Event Loop часто замінюють на ",[3398,3966,3967],{},[3438,3968,3969],{},"uvloop"," — альтернативну бібліотеку, написану на Cython, яка обгортає надшвидку системну бібліотеку ",[3438,3972,3973],{},"libuv"," (що використовується в Node.js). ",[3438,3976,3969],{}," робить асинхронний Python у 2-4 рази швидшим, наближаючи його продуктивність до Go та Node.js.",[3394,3979,3980],{},"Розглянемо базовий приклад конкурентного чергування виконання корутин у циклі подій:",[3564,3982,3984],{"className":3566,"code":3983,"language":3568,"meta":3569,"style":3569},"# event_loop_anatomy.py\nimport asyncio\n\nasync def say_hello() -> None:\n    print(\"Привіт!\")           # Крок 1\n    # Корутина реєструє подію таймера на 1 сек і добровільно віддає контроль Event Loop\n    await asyncio.sleep(1)\n    print(\"Пройшла секунда\")   # Крок 2 (виконується після спрацьовування таймера)\n\nasync def count() -> None:\n    for i in range(3):\n        print(f\"  Рахую: {i}\")\n        # Корутина реєструє подію таймера на 0.3 сек і віддає контроль\n        await asyncio.sleep(0.3)\n\nasync def main() -> None:\n    # Запускаємо обидві корутини конкурувати за процесорний час\n    await asyncio.gather(say_hello(), count())\n\n# Створюємо подієвий цикл, запускаємо головну корутину та закриваємо цикл\nasyncio.run(main())\n",[3438,3985,3986,3991,3997,4001,4019,4034,4039,4053,4068,4072,4087,4109,4132,4137,4149,4153,4168,4173,4180,4184,4189],{"__ignoreMap":3569},[3573,3987,3988],{"class":3575,"line":3576},[3573,3989,3990],{"class":3579},"# event_loop_anatomy.py\n",[3573,3992,3993,3995],{"class":3575,"line":3583},[3573,3994,3587],{"class":3586},[3573,3996,3591],{"class":3590},[3573,3998,3999],{"class":3575,"line":3594},[3573,4000,3598],{"emptyLinePlaceholder":3597},[3573,4002,4003,4006,4009,4012,4015,4017],{"class":3575,"line":3601},[3573,4004,4005],{"class":3604},"async",[3573,4007,4008],{"class":3604}," def",[3573,4010,4011],{"class":3608}," say_hello",[3573,4013,4014],{"class":3590},"() -> ",[3573,4016,3629],{"class":3604},[3573,4018,3632],{"class":3590},[3573,4020,4021,4023,4025,4028,4031],{"class":3575,"line":3635},[3573,4022,3645],{"class":3608},[3573,4024,3612],{"class":3590},[3573,4026,4027],{"class":3638},"\"Привіт!\"",[3573,4029,4030],{"class":3590},")           ",[3573,4032,4033],{"class":3579},"# Крок 1\n",[3573,4035,4036],{"class":3575,"line":3642},[3573,4037,4038],{"class":3579},"    # Корутина реєструє подію таймера на 1 сек і добровільно віддає контроль Event Loop\n",[3573,4040,4041,4044,4047,4051],{"class":3575,"line":3671},[3573,4042,4043],{"class":3586},"    await",[3573,4045,4046],{"class":3590}," asyncio.sleep(",[3573,4048,4050],{"class":4049},"sJj4R","1",[3573,4052,3668],{"class":3590},[3573,4054,4055,4057,4059,4062,4065],{"class":3575,"line":3676},[3573,4056,3645],{"class":3608},[3573,4058,3612],{"class":3590},[3573,4060,4061],{"class":3638},"\"Пройшла секунда\"",[3573,4063,4064],{"class":3590},")   ",[3573,4066,4067],{"class":3579},"# Крок 2 (виконується після спрацьовування таймера)\n",[3573,4069,4070],{"class":3575,"line":3695},[3573,4071,3598],{"emptyLinePlaceholder":3597},[3573,4073,4074,4076,4078,4081,4083,4085],{"class":3575,"line":3701},[3573,4075,4005],{"class":3604},[3573,4077,4008],{"class":3604},[3573,4079,4080],{"class":3608}," count",[3573,4082,4014],{"class":3590},[3573,4084,3629],{"class":3604},[3573,4086,3632],{"class":3590},[3573,4088,4089,4092,4095,4098,4101,4103,4106],{"class":3575,"line":3721},[3573,4090,4091],{"class":3586},"    for",[3573,4093,4094],{"class":3590}," i ",[3573,4096,4097],{"class":3586},"in",[3573,4099,4100],{"class":3608}," range",[3573,4102,3612],{"class":3590},[3573,4104,4105],{"class":4049},"3",[3573,4107,4108],{"class":3590},"):\n",[3573,4110,4111,4114,4116,4118,4121,4123,4126,4128,4130],{"class":3575,"line":3727},[3573,4112,4113],{"class":3608},"        print",[3573,4115,3612],{"class":3590},[3573,4117,3650],{"class":3604},[3573,4119,4120],{"class":3638},"\"  Рахую: ",[3573,4122,3656],{"class":3604},[3573,4124,4125],{"class":3590},"i",[3573,4127,3662],{"class":3604},[3573,4129,3665],{"class":3638},[3573,4131,3668],{"class":3590},[3573,4133,4134],{"class":3575,"line":3816},[3573,4135,4136],{"class":3579},"        # Корутина реєструє подію таймера на 0.3 сек і віддає контроль\n",[3573,4138,4139,4142,4144,4147],{"class":3575,"line":3822},[3573,4140,4141],{"class":3586},"        await",[3573,4143,4046],{"class":3590},[3573,4145,4146],{"class":4049},"0.3",[3573,4148,3668],{"class":3590},[3573,4150,4151],{"class":3575,"line":3827},[3573,4152,3598],{"emptyLinePlaceholder":3597},[3573,4154,4155,4157,4159,4162,4164,4166],{"class":3575,"line":3833},[3573,4156,4005],{"class":3604},[3573,4158,4008],{"class":3604},[3573,4160,4161],{"class":3608}," main",[3573,4163,4014],{"class":3590},[3573,4165,3629],{"class":3604},[3573,4167,3632],{"class":3590},[3573,4169,4170],{"class":3575,"line":3839},[3573,4171,4172],{"class":3579},"    # Запускаємо обидві корутини конкурувати за процесорний час\n",[3573,4174,4175,4177],{"class":3575,"line":3845},[3573,4176,4043],{"class":3586},[3573,4178,4179],{"class":3590}," asyncio.gather(say_hello(), count())\n",[3573,4181,4182],{"class":3575,"line":3851},[3573,4183,3598],{"emptyLinePlaceholder":3597},[3573,4185,4186],{"class":3575,"line":3856},[3573,4187,4188],{"class":3579},"# Створюємо подієвий цикл, запускаємо головну корутину та закриваємо цикл\n",[3573,4190,4191],{"class":3575,"line":3862},[3573,4192,4193],{"class":3590},"asyncio.run(main())\n",[4195,4196,4198,4210,4214,4218,4222,4226],"terminal-preview",{"title":4197},"python event_loop_anatomy.py",[4199,4200,4202,4207,4208],"div",{"className":4201},[3575],[3573,4203,4206],{"className":4204},[4205],"opacity-40","$"," ",[3398,4209,4197],{},[4199,4211,4213],{"className":4212},[3575],"Привіт!",[4199,4215,4217],{"className":4216},[3575],"  Рахую: 0",[4199,4219,4221],{"className":4220},[3575],"  Рахую: 1",[4199,4223,4225],{"className":4224},[3575],"  Рахую: 2",[4199,4227,4229],{"className":4228},[3575],"Пройшла секунда",[3394,4231,4232,4233,4236,4237,4240,4241,4244,4245,4247,4248,4250,4251,3507],{},"Зверніть увагу: ",[3438,4234,4235],{},"say_hello"," і ",[3438,4238,4239],{},"count"," виконуються у ",[3398,4242,4243],{},"чергуванні"," — поки ",[3438,4246,4235],{}," чекає 1 секунду, ",[3438,4249,4239],{}," тричі встигає вивести значення. Це і є кооперативна конкурентність: один потік, але ілюзія «одночасності» за рахунок перемикання у точках ",[3438,4252,3488],{},[3461,4254,4256,4257,4259],{"id":4255},"що-відбувається-у-точці-await-глибинний-аналіз-життєвого-циклу-корутини","Що відбувається у точці ",[3438,4258,3488],{}," (Глибинний аналіз життєвого циклу корутини)",[3394,4261,4262,4263,4265],{},"Коли інтерпретатор Python зустрічає ключове слово ",[3438,4264,3488],{},", він не просто «зупиняє» виконання. Це складна взаємодія між генераторним кадром (frame) корутини, об'єктом, який ми очікуємо (awaitable), та подієвим циклом (Event Loop).",[4267,4268,4270],"h4",{"id":4269},"анатомія-призупинення-та-відновлення","Анатомія призупинення та відновлення",[3394,4272,4273,4274,4276,4277,4279],{},"Під капотом Python корутина — це розширена версія генератора (PEP 492). Ключове слово ",[3438,4275,3488],{}," працює аналогічно до ",[3438,4278,3540],{},", але зі строгою семантикою та додатковими перевірками типів.",[3422,4281,4282,4304,4339,4361,4387],{},[3425,4283,4284,4291,4292,4295,4296,4299,4300,4303],{},[3398,4285,4286,4287,4290],{},"Ініціація очікування (",[3438,4288,4289],{},"awaitable.__await__()",")",":\nКонструкція ",[3438,4293,4294],{},"await X"," вимагає, щоб об'єкт ",[3438,4297,4298],{},"X"," підтримував протокол асинхронного очікування, тобто реалізував магічний метод ",[3438,4301,4302],{},"__await__()",". Цей метод має повертати ітератор (найчастіше це об'єкт-генератор).",[3425,4305,4306,4309,4310,4313,4314,4317,4318,4320,4321,4313,4324,4327,4328,4331,4332,4334,4335,4338],{},[3398,4307,4308],{},"Передача контролю подієвому циклу",":\nКорутина-батько виконує крок ",[3438,4311,4312],{},"next()"," або ",[3438,4315,4316],{},"send(None)"," для ітератора, отриманого з ",[3438,4319,4302],{},". Якщо очікувана операція (наприклад, асинхронне введення-виведення або таймер) ще не завершена, ітератор генерує спеціальний об'єкт (зазвичай це ",[3438,4322,4323],{},"asyncio.Future",[3438,4325,4326],{},"asyncio.Task",") і призупиняє своє виконання через інструкцію ",[3438,4329,4330],{},"yield",".\nЦей ",[3438,4333,4330],{}," прокидає об'єкт ",[3438,4336,4337],{},"Future"," вгору по стеку викликів аж до самого Event Loop.",[3425,4340,4341,4344,4345,4347,4348,4350,4351,4354,4355,4357,4358,4360],{},[3398,4342,4343],{},"Реєстрація події в ОС",":\nEvent Loop отримує цей ",[3438,4346,4337],{}," і розуміє, що виконання корутини залежить від завершення певної операції. Він реєструє асинхронний callback на цей ",[3438,4349,4337],{}," (метод ",[3438,4352,4353],{},"add_done_callback()",") та зв'язує його із відповідним системним дескриптором (через ",[3438,4356,3944],{},"\u002F",[3438,4359,3952],{},") або таймером.\nПоки подія не відбудеться, Event Loop повністю ігнорує дану корутину і виконує інші готові завдання в Ready Queue.",[3425,4362,4363,4373,4374,4376,4377,4380,4381,4384,4385,3507],{},[3398,4364,4365,4366,4369,4370,4290],{},"Пробудження та відновлення виконання (",[3438,4367,4368],{},"send()"," \u002F ",[3438,4371,4372],{},"throw()",":\nКоли операційна система сигналізує про завершення I\u002FO події, Event Loop змінює стан ",[3438,4375,4337],{}," на «виконано» (set result) та викликає раніше зареєстрований callback. Цей callback переміщує корутину в чергу готових до виконання.\nНа наступній ітерації циклу Event Loop викликає метод ",[3438,4378,4379],{},".send(result_value)"," (або ",[3438,4382,4383],{},".throw(exception)"," у випадку помилки) на корутині. Це відновлює її виконання з точної точки ",[3438,4386,3488],{},[3425,4388,4389,4395,4396,4399,4400,4402,4403,4405,4406,4409,4410,4413,4414,3507],{},[3398,4390,4391,4392,4290],{},"Завершення та отримання результату (",[3438,4393,4394],{},"StopIteration",":\nКорутина завершується (досягає ",[3438,4397,4398],{},"return","), CPython ініціює виняток ",[3438,4401,4394],{},". Значення, повернуте через ",[3438,4404,4398],{},", записується в атрибут ",[3438,4407,4408],{},"value"," цього винятку (",[3438,4411,4412],{},"StopIteration.value",").\nEvent Loop перехоплює цей виняток, витягує результат та повертає його у батьківську корутину як результат виразу ",[3438,4415,3488],{},[3394,4417,4418],{},"Розглянемо послідовність взаємодії у вигляді діаграми:",[3747,4420,4421],{},[3564,4422,4424],{"className":3751,"code":4423,"language":3753,"meta":3569,"style":3569},"@startuml\nskinparam style plain\nskinparam linetype ortho\nskinparam responseMessageBelowArrow true\n\ntitle Життєвий цикл призупинення та відновлення корутини\n\nparticipant \"Event Loop\" as EL\nparticipant \"Корутина (Parent)\" as Parent\nparticipant \"Awaitable (Future\u002FTimer)\" as Fut\nparticipant \"Мультиплексор ОС\" as OS\n\nEL -> Parent : send(None) (Активація\u002FВідновлення)\nactivate Parent\n\nParent -> Fut : __await__()\nactivate Fut\nFut --> Parent : Awaitable Iterator\ndeactivate Fut\n\nParent -> Parent : Отримання чергового кроку з ітератора\n\nParent -> EL : yield Future (Передача контролю)\ndeactivate Parent\nnote right: Кадр (Frame) корутини заморожується\n\nEL -> Fut : add_done_callback(wakeup)\nEL -> OS : Реєстрація дескриптора \u002F таймера\nactivate OS\n\nnote over EL, OS : Event Loop продовжує обробку інших завдань...\n\nOS --> EL : Сигнал: I\u002FO подія готова \u002F Час сплив\ndeactivate OS\n\nEL -> Fut : set_result(data)\nactivate Fut\ndeactivate Fut\n\nEL -> EL : Виклик wakeup() та додавання в Ready Queue\nEL -> Parent : send(data) (Відновлення кадру)\nactivate Parent\n\nParent -> Parent : Розпакування результату з StopIteration\n\nParent --> EL : StopIteration(return_value)\ndeactivate Parent\nnote right: Корутина завершила роботу\n\n@enduml\n",[3438,4425,4426,4430,4434,4438,4443,4447,4452,4456,4461,4466,4471,4476,4480,4485,4490,4494,4499,4504,4509,4514,4518,4523,4527,4532,4537,4542,4546,4551,4556,4561,4565,4570,4574,4580,4586,4591,4597,4602,4607,4612,4618,4624,4629,4634,4640,4645,4651,4656,4662,4667],{"__ignoreMap":3569},[3573,4427,4428],{"class":3575,"line":3576},[3573,4429,3760],{},[3573,4431,4432],{"class":3575,"line":3583},[3573,4433,3765],{},[3573,4435,4436],{"class":3575,"line":3594},[3573,4437,3770],{},[3573,4439,4440],{"class":3575,"line":3601},[3573,4441,4442],{},"skinparam responseMessageBelowArrow true\n",[3573,4444,4445],{"class":3575,"line":3635},[3573,4446,3598],{"emptyLinePlaceholder":3597},[3573,4448,4449],{"class":3575,"line":3642},[3573,4450,4451],{},"title Життєвий цикл призупинення та відновлення корутини\n",[3573,4453,4454],{"class":3575,"line":3671},[3573,4455,3598],{"emptyLinePlaceholder":3597},[3573,4457,4458],{"class":3575,"line":3676},[3573,4459,4460],{},"participant \"Event Loop\" as EL\n",[3573,4462,4463],{"class":3575,"line":3695},[3573,4464,4465],{},"participant \"Корутина (Parent)\" as Parent\n",[3573,4467,4468],{"class":3575,"line":3701},[3573,4469,4470],{},"participant \"Awaitable (Future\u002FTimer)\" as Fut\n",[3573,4472,4473],{"class":3575,"line":3721},[3573,4474,4475],{},"participant \"Мультиплексор ОС\" as OS\n",[3573,4477,4478],{"class":3575,"line":3727},[3573,4479,3598],{"emptyLinePlaceholder":3597},[3573,4481,4482],{"class":3575,"line":3816},[3573,4483,4484],{},"EL -> Parent : send(None) (Активація\u002FВідновлення)\n",[3573,4486,4487],{"class":3575,"line":3822},[3573,4488,4489],{},"activate Parent\n",[3573,4491,4492],{"class":3575,"line":3827},[3573,4493,3598],{"emptyLinePlaceholder":3597},[3573,4495,4496],{"class":3575,"line":3833},[3573,4497,4498],{},"Parent -> Fut : __await__()\n",[3573,4500,4501],{"class":3575,"line":3839},[3573,4502,4503],{},"activate Fut\n",[3573,4505,4506],{"class":3575,"line":3845},[3573,4507,4508],{},"Fut --> Parent : Awaitable Iterator\n",[3573,4510,4511],{"class":3575,"line":3851},[3573,4512,4513],{},"deactivate Fut\n",[3573,4515,4516],{"class":3575,"line":3856},[3573,4517,3598],{"emptyLinePlaceholder":3597},[3573,4519,4520],{"class":3575,"line":3862},[3573,4521,4522],{},"Parent -> Parent : Отримання чергового кроку з ітератора\n",[3573,4524,4525],{"class":3575,"line":3868},[3573,4526,3598],{"emptyLinePlaceholder":3597},[3573,4528,4529],{"class":3575,"line":3874},[3573,4530,4531],{},"Parent -> EL : yield Future (Передача контролю)\n",[3573,4533,4534],{"class":3575,"line":3880},[3573,4535,4536],{},"deactivate Parent\n",[3573,4538,4539],{"class":3575,"line":3886},[3573,4540,4541],{},"note right: Кадр (Frame) корутини заморожується\n",[3573,4543,4544],{"class":3575,"line":3891},[3573,4545,3598],{"emptyLinePlaceholder":3597},[3573,4547,4548],{"class":3575,"line":3897},[3573,4549,4550],{},"EL -> Fut : add_done_callback(wakeup)\n",[3573,4552,4553],{"class":3575,"line":3902},[3573,4554,4555],{},"EL -> OS : Реєстрація дескриптора \u002F таймера\n",[3573,4557,4558],{"class":3575,"line":3908},[3573,4559,4560],{},"activate OS\n",[3573,4562,4563],{"class":3575,"line":3913},[3573,4564,3598],{"emptyLinePlaceholder":3597},[3573,4566,4567],{"class":3575,"line":3919},[3573,4568,4569],{},"note over EL, OS : Event Loop продовжує обробку інших завдань...\n",[3573,4571,4572],{"class":3575,"line":3925},[3573,4573,3598],{"emptyLinePlaceholder":3597},[3573,4575,4577],{"class":3575,"line":4576},33,[3573,4578,4579],{},"OS --> EL : Сигнал: I\u002FO подія готова \u002F Час сплив\n",[3573,4581,4583],{"class":3575,"line":4582},34,[3573,4584,4585],{},"deactivate OS\n",[3573,4587,4589],{"class":3575,"line":4588},35,[3573,4590,3598],{"emptyLinePlaceholder":3597},[3573,4592,4594],{"class":3575,"line":4593},36,[3573,4595,4596],{},"EL -> Fut : set_result(data)\n",[3573,4598,4600],{"class":3575,"line":4599},37,[3573,4601,4503],{},[3573,4603,4605],{"class":3575,"line":4604},38,[3573,4606,4513],{},[3573,4608,4610],{"class":3575,"line":4609},39,[3573,4611,3598],{"emptyLinePlaceholder":3597},[3573,4613,4615],{"class":3575,"line":4614},40,[3573,4616,4617],{},"EL -> EL : Виклик wakeup() та додавання в Ready Queue\n",[3573,4619,4621],{"class":3575,"line":4620},41,[3573,4622,4623],{},"EL -> Parent : send(data) (Відновлення кадру)\n",[3573,4625,4627],{"class":3575,"line":4626},42,[3573,4628,4489],{},[3573,4630,4632],{"class":3575,"line":4631},43,[3573,4633,3598],{"emptyLinePlaceholder":3597},[3573,4635,4637],{"class":3575,"line":4636},44,[3573,4638,4639],{},"Parent -> Parent : Розпакування результату з StopIteration\n",[3573,4641,4643],{"class":3575,"line":4642},45,[3573,4644,3598],{"emptyLinePlaceholder":3597},[3573,4646,4648],{"class":3575,"line":4647},46,[3573,4649,4650],{},"Parent --> EL : StopIteration(return_value)\n",[3573,4652,4654],{"class":3575,"line":4653},47,[3573,4655,4536],{},[3573,4657,4659],{"class":3575,"line":4658},48,[3573,4660,4661],{},"note right: Корутина завершила роботу\n",[3573,4663,4665],{"class":3575,"line":4664},49,[3573,4666,3598],{"emptyLinePlaceholder":3597},[3573,4668,4670],{"class":3575,"line":4669},50,[3573,4671,3928],{},[4267,4673,4675,4676,4290],{"id":4674},"синхронне-проти-конкурентного-виконання-аналіз-await_mechanicspy","Синхронне проти конкурентного виконання (Аналіз ",[3438,4677,4678],{},"await_mechanics.py",[3394,4680,4681,4682,4684,4685,4688],{},"Асинхронність не означає автоматичну паралельність. Якщо ви просто ставите ",[3438,4683,3488],{}," перед кожним викликом корутини, вони будуть виконуватися ",[3398,4686,4687],{},"послідовно",", оскільки кожна наступна корутина чекатиме завершення попередньої.",[3394,4690,4691,4692,4695],{},"Розглянемо практичний приклад, який наочно демонструє різницю у часі виконання при послідовному очікуванні та при використанні конкурентного групування через ",[3438,4693,4694],{},"asyncio.gather()",":",[3564,4697,4699],{"className":3566,"code":4698,"language":3568,"meta":3569,"style":3569},"# await_mechanics.py\nimport asyncio\nimport time\n\nasync def fast_io() -> str:\n    \"\"\"Симулює швидку I\u002FO операцію (10 мс).\"\"\"\n    await asyncio.sleep(0.01)\n    return \"fast result\"\n\nasync def slow_io() -> str:\n    \"\"\"Симулює повільну I\u002FO операцію (500 мс).\"\"\"\n    await asyncio.sleep(0.5)\n    return \"slow result\"\n\nasync def demonstrate_await() -> None:\n    print(\"=== Послідовне виконання (await кожного окремо) ===\")\n    t0 = time.perf_counter()\n    # 1. Чекаємо завершення fast_io()\n    r1 = await fast_io()\n    # 2. Тільки після цього починаємо і чекаємо slow_io()\n    r2 = await slow_io()\n    print(f\"Результати: {r1}, {r2}\")\n    print(f\"Час виконання: {time.perf_counter() - t0:.4f}s\")  # Очікувано ~0.51s\n\n    print(\"\\n=== Конкурентне виконання (asyncio.gather) ===\")\n    t0 = time.perf_counter()\n    # Запускаємо обидві корутини одночасно в Event Loop і чекаємо на їх результати\n    r1, r2 = await asyncio.gather(fast_io(), slow_io())\n    print(f\"Результати: {r1}, {r2}\")\n    print(f\"Час виконання: {time.perf_counter() - t0:.4f}s\")  # Очікувано ~0.50s (лімітується slow_io)\n\nasyncio.run(demonstrate_await())\n",[3438,4700,4701,4706,4712,4719,4723,4739,4744,4755,4763,4767,4782,4787,4798,4805,4809,4824,4835,4840,4845,4855,4860,4870,4902,4930,4934,4949,4953,4958,4968,4996,5019,5023],{"__ignoreMap":3569},[3573,4702,4703],{"class":3575,"line":3576},[3573,4704,4705],{"class":3579},"# await_mechanics.py\n",[3573,4707,4708,4710],{"class":3575,"line":3583},[3573,4709,3587],{"class":3586},[3573,4711,3591],{"class":3590},[3573,4713,4714,4716],{"class":3575,"line":3594},[3573,4715,3587],{"class":3586},[3573,4717,4718],{"class":3590}," time\n",[3573,4720,4721],{"class":3575,"line":3601},[3573,4722,3598],{"emptyLinePlaceholder":3597},[3573,4724,4725,4727,4729,4732,4734,4737],{"class":3575,"line":3635},[3573,4726,4005],{"class":3604},[3573,4728,4008],{"class":3604},[3573,4730,4731],{"class":3608}," fast_io",[3573,4733,4014],{"class":3590},[3573,4735,4736],{"class":3622},"str",[3573,4738,3632],{"class":3590},[3573,4740,4741],{"class":3575,"line":3642},[3573,4742,4743],{"class":3638},"    \"\"\"Симулює швидку I\u002FO операцію (10 мс).\"\"\"\n",[3573,4745,4746,4748,4750,4753],{"class":3575,"line":3671},[3573,4747,4043],{"class":3586},[3573,4749,4046],{"class":3590},[3573,4751,4752],{"class":4049},"0.01",[3573,4754,3668],{"class":3590},[3573,4756,4757,4760],{"class":3575,"line":3676},[3573,4758,4759],{"class":3586},"    return",[3573,4761,4762],{"class":3638}," \"fast result\"\n",[3573,4764,4765],{"class":3575,"line":3695},[3573,4766,3598],{"emptyLinePlaceholder":3597},[3573,4768,4769,4771,4773,4776,4778,4780],{"class":3575,"line":3701},[3573,4770,4005],{"class":3604},[3573,4772,4008],{"class":3604},[3573,4774,4775],{"class":3608}," slow_io",[3573,4777,4014],{"class":3590},[3573,4779,4736],{"class":3622},[3573,4781,3632],{"class":3590},[3573,4783,4784],{"class":3575,"line":3721},[3573,4785,4786],{"class":3638},"    \"\"\"Симулює повільну I\u002FO операцію (500 мс).\"\"\"\n",[3573,4788,4789,4791,4793,4796],{"class":3575,"line":3727},[3573,4790,4043],{"class":3586},[3573,4792,4046],{"class":3590},[3573,4794,4795],{"class":4049},"0.5",[3573,4797,3668],{"class":3590},[3573,4799,4800,4802],{"class":3575,"line":3816},[3573,4801,4759],{"class":3586},[3573,4803,4804],{"class":3638}," \"slow result\"\n",[3573,4806,4807],{"class":3575,"line":3822},[3573,4808,3598],{"emptyLinePlaceholder":3597},[3573,4810,4811,4813,4815,4818,4820,4822],{"class":3575,"line":3827},[3573,4812,4005],{"class":3604},[3573,4814,4008],{"class":3604},[3573,4816,4817],{"class":3608}," demonstrate_await",[3573,4819,4014],{"class":3590},[3573,4821,3629],{"class":3604},[3573,4823,3632],{"class":3590},[3573,4825,4826,4828,4830,4833],{"class":3575,"line":3833},[3573,4827,3645],{"class":3608},[3573,4829,3612],{"class":3590},[3573,4831,4832],{"class":3638},"\"=== Послідовне виконання (await кожного окремо) ===\"",[3573,4834,3668],{"class":3590},[3573,4836,4837],{"class":3575,"line":3839},[3573,4838,4839],{"class":3590},"    t0 = time.perf_counter()\n",[3573,4841,4842],{"class":3575,"line":3845},[3573,4843,4844],{"class":3579},"    # 1. Чекаємо завершення fast_io()\n",[3573,4846,4847,4850,4852],{"class":3575,"line":3851},[3573,4848,4849],{"class":3590},"    r1 = ",[3573,4851,3488],{"class":3586},[3573,4853,4854],{"class":3590}," fast_io()\n",[3573,4856,4857],{"class":3575,"line":3856},[3573,4858,4859],{"class":3579},"    # 2. Тільки після цього починаємо і чекаємо slow_io()\n",[3573,4861,4862,4865,4867],{"class":3575,"line":3862},[3573,4863,4864],{"class":3590},"    r2 = ",[3573,4866,3488],{"class":3586},[3573,4868,4869],{"class":3590}," slow_io()\n",[3573,4871,4872,4874,4876,4878,4881,4883,4886,4888,4891,4893,4896,4898,4900],{"class":3575,"line":3868},[3573,4873,3645],{"class":3608},[3573,4875,3612],{"class":3590},[3573,4877,3650],{"class":3604},[3573,4879,4880],{"class":3638},"\"Результати: ",[3573,4882,3656],{"class":3604},[3573,4884,4885],{"class":3590},"r1",[3573,4887,3662],{"class":3604},[3573,4889,4890],{"class":3638},", ",[3573,4892,3656],{"class":3604},[3573,4894,4895],{"class":3590},"r2",[3573,4897,3662],{"class":3604},[3573,4899,3665],{"class":3638},[3573,4901,3668],{"class":3590},[3573,4903,4904,4906,4908,4910,4913,4915,4918,4921,4924,4927],{"class":3575,"line":3874},[3573,4905,3645],{"class":3608},[3573,4907,3612],{"class":3590},[3573,4909,3650],{"class":3604},[3573,4911,4912],{"class":3638},"\"Час виконання: ",[3573,4914,3656],{"class":3604},[3573,4916,4917],{"class":3590},"time.perf_counter() - t0",[3573,4919,4920],{"class":3604},":.4f}",[3573,4922,4923],{"class":3638},"s\"",[3573,4925,4926],{"class":3590},")  ",[3573,4928,4929],{"class":3579},"# Очікувано ~0.51s\n",[3573,4931,4932],{"class":3575,"line":3880},[3573,4933,3598],{"emptyLinePlaceholder":3597},[3573,4935,4936,4938,4940,4942,4944,4947],{"class":3575,"line":3886},[3573,4937,3645],{"class":3608},[3573,4939,3612],{"class":3590},[3573,4941,3665],{"class":3638},[3573,4943,3714],{"class":3713},[3573,4945,4946],{"class":3638},"=== Конкурентне виконання (asyncio.gather) ===\"",[3573,4948,3668],{"class":3590},[3573,4950,4951],{"class":3575,"line":3891},[3573,4952,4839],{"class":3590},[3573,4954,4955],{"class":3575,"line":3897},[3573,4956,4957],{"class":3579},"    # Запускаємо обидві корутини одночасно в Event Loop і чекаємо на їх результати\n",[3573,4959,4960,4963,4965],{"class":3575,"line":3902},[3573,4961,4962],{"class":3590},"    r1, r2 = ",[3573,4964,3488],{"class":3586},[3573,4966,4967],{"class":3590}," asyncio.gather(fast_io(), slow_io())\n",[3573,4969,4970,4972,4974,4976,4978,4980,4982,4984,4986,4988,4990,4992,4994],{"class":3575,"line":3908},[3573,4971,3645],{"class":3608},[3573,4973,3612],{"class":3590},[3573,4975,3650],{"class":3604},[3573,4977,4880],{"class":3638},[3573,4979,3656],{"class":3604},[3573,4981,4885],{"class":3590},[3573,4983,3662],{"class":3604},[3573,4985,4890],{"class":3638},[3573,4987,3656],{"class":3604},[3573,4989,4895],{"class":3590},[3573,4991,3662],{"class":3604},[3573,4993,3665],{"class":3638},[3573,4995,3668],{"class":3590},[3573,4997,4998,5000,5002,5004,5006,5008,5010,5012,5014,5016],{"class":3575,"line":3913},[3573,4999,3645],{"class":3608},[3573,5001,3612],{"class":3590},[3573,5003,3650],{"class":3604},[3573,5005,4912],{"class":3638},[3573,5007,3656],{"class":3604},[3573,5009,4917],{"class":3590},[3573,5011,4920],{"class":3604},[3573,5013,4923],{"class":3638},[3573,5015,4926],{"class":3590},[3573,5017,5018],{"class":3579},"# Очікувано ~0.50s (лімітується slow_io)\n",[3573,5020,5021],{"class":3575,"line":3919},[3573,5022,3598],{"emptyLinePlaceholder":3597},[3573,5024,5025],{"class":3575,"line":3925},[3573,5026,5027],{"class":3590},"asyncio.run(demonstrate_await())\n",[4195,5029,5031,5035,5039,5053,5056,5060,5063],{"title":5030},"python await_mechanics.py",[4199,5032,5034],{"className":5033},[3575],"=== Послідовне виконання (await кожного окремо) ===",[4199,5036,5038],{"className":5037},[3575],"Результати: fast result, slow result",[4199,5040,5042,5043,5048,5049],{"className":5041},[3575],"Час виконання: ",[3573,5044,5047],{"className":5045},[5046],"text-rose-400","0.5100s","  ",[3573,5050,5052],{"className":5051},[4205],"← час сумується (t1 + t2)",[4199,5054],{"className":5055},[3575],[4199,5057,5059],{"className":5058},[3575],"=== Конкурентне виконання (asyncio.gather) ===",[4199,5061,5038],{"className":5062},[3575],[4199,5064,5042,5066,5048,5071],{"className":5065},[3575],[3573,5067,5070],{"className":5068},[5069],"text-green-400","0.5000s",[3573,5072,5074],{"className":5073},[4205],"← визначається лише найповільнішою задачею max(t1, t2)",[5076,5077,5078,4291,5081,5084,5085,4890,5087,5090,5091,3507],"important",{},[3398,5079,5080],{},"Фундаментальне правило asyncio",[3438,5082,5083],{},"await coroutine()"," призупиняє поточну корутину до завершення викликаної корутини. Це є лінійним послідовним ланцюжком. Для запуску завдань у конкурентному режимі (коли кілька I\u002FO-операцій очікуються одночасно) необхідно передати їх під контроль Event Loop за допомогою ",[3438,5086,4694],{},[3438,5088,5089],{},"asyncio.create_task()",", або контекстного менеджера ",[3438,5092,5093],{},"asyncio.TaskGroup",[3458,5095],{},[3389,5097,5099,5100,4236,5102,5104],{"id":5098},"частина-ii-async-def-і-await-синтаксис-і-семантика","Частина II: ",[3438,5101,3553],{},[3438,5103,3488],{}," — синтаксис і семантика",[3394,5106,5107,5108,3554,5110,5112],{},"Асинхронне програмування в Python базується на чіткому розділенні синхронного та асинхронного контекстів. Синтаксичні конструкції ",[3438,5109,3553],{},[3438,5111,3488],{}," забезпечують декларативний опис точок перемикання контексту, дозволяючи писати асинхронний код у лінійному імперативному стилі.",[3458,5114],{},[3461,5116,5118],{"id":5117},"що-таке-корутина-під-капотом-coroutine-object","Що таке корутина під капотом (Coroutine Object)",[3394,5120,5121,5122,5124,5125,5128,5129,5132,5133,5136],{},"Використання ключового слова ",[3438,5123,3553],{}," перед сигнатурою функції кардинально змінює її поведінку. Замість звичайної функції (",[3438,5126,5127],{},"function","), інтерпретатор створює ",[3398,5130,5131],{},"корутинну функцію"," (",[3438,5134,5135],{},"coroutine function",").",[3394,5138,5139,5140,5143,5144,5147],{},"Коли ви викликаєте корутинну функцію, код всередині її тіла ",[3398,5141,5142],{},"не починає виконуватись",". Замість цього інтерпретатор повертає об'єкт корутини (",[3438,5145,5146],{},"coroutine object","). Цей об'єкт є обгорткою над станом виконання функції (стеком локальних змінних, вказівником інструкцій та кадром виконання).",[3394,5149,5150,5151,4695],{},"Для перевірки типу корутин та корутинних функцій використовується вбудований модуль ",[3438,5152,5153],{},"inspect",[3564,5155,5157],{"className":3566,"code":5156,"language":3568,"meta":3569,"style":3569},"# coroutine_anatomy.py\nimport asyncio\nimport inspect\n\nasync def greet(name: str) -> str:\n    await asyncio.sleep(0.1)\n    return f\"Привіт, {name}!\"\n\n# 1. Виклик корутинної функції повертає об'єкт корутини (тіло не виконується)\ncoro = greet(\"Іван\")\nprint(type(coro))                 # \u003Cclass 'coroutine'>\n\n# 2. Перевірка об'єкта та функції за допомогою inspect\nprint(inspect.iscoroutinefunction(greet))  # True (сама функція)\nprint(inspect.iscoroutine(coro))          # True (об'єкт, отриманий від виклику)\nprint(inspect.isawaitable(coro))          # True (об'єкт підтримує протокол await)\n\n# 3. Для виконання корутини потрібен Event Loop.\n# asyncio.run() створює loop, реєструє корутину та запускає її.\nresult = asyncio.run(greet(\"Марія\"))\nprint(result)  # \"Привіт, Марія!\"\n\n# 4. Або ми викликаємо її зсередини іншої асинхронної функції через await:\nasync def main():\n    result = await greet(\"Олег\")  # відновлення кадру корутини greet\n    print(result)\n\nasyncio.run(main())\n",[3438,5158,5159,5164,5170,5177,5181,5205,5216,5235,5239,5244,5254,5270,5274,5279,5289,5299,5309,5313,5318,5323,5334,5344,5348,5353,5364,5382,5389,5393],{"__ignoreMap":3569},[3573,5160,5161],{"class":3575,"line":3576},[3573,5162,5163],{"class":3579},"# coroutine_anatomy.py\n",[3573,5165,5166,5168],{"class":3575,"line":3583},[3573,5167,3587],{"class":3586},[3573,5169,3591],{"class":3590},[3573,5171,5172,5174],{"class":3575,"line":3594},[3573,5173,3587],{"class":3586},[3573,5175,5176],{"class":3590}," inspect\n",[3573,5178,5179],{"class":3575,"line":3601},[3573,5180,3598],{"emptyLinePlaceholder":3597},[3573,5182,5183,5185,5187,5190,5192,5195,5197,5199,5201,5203],{"class":3575,"line":3635},[3573,5184,4005],{"class":3604},[3573,5186,4008],{"class":3604},[3573,5188,5189],{"class":3608}," greet",[3573,5191,3612],{"class":3590},[3573,5193,5194],{"class":3615},"name",[3573,5196,3619],{"class":3590},[3573,5198,4736],{"class":3622},[3573,5200,3626],{"class":3590},[3573,5202,4736],{"class":3622},[3573,5204,3632],{"class":3590},[3573,5206,5207,5209,5211,5214],{"class":3575,"line":3642},[3573,5208,4043],{"class":3586},[3573,5210,4046],{"class":3590},[3573,5212,5213],{"class":4049},"0.1",[3573,5215,3668],{"class":3590},[3573,5217,5218,5220,5223,5226,5228,5230,5232],{"class":3575,"line":3671},[3573,5219,4759],{"class":3586},[3573,5221,5222],{"class":3604}," f",[3573,5224,5225],{"class":3638},"\"Привіт, ",[3573,5227,3656],{"class":3604},[3573,5229,5194],{"class":3590},[3573,5231,3662],{"class":3604},[3573,5233,5234],{"class":3638},"!\"\n",[3573,5236,5237],{"class":3575,"line":3676},[3573,5238,3598],{"emptyLinePlaceholder":3597},[3573,5240,5241],{"class":3575,"line":3695},[3573,5242,5243],{"class":3579},"# 1. Виклик корутинної функції повертає об'єкт корутини (тіло не виконується)\n",[3573,5245,5246,5249,5252],{"class":3575,"line":3701},[3573,5247,5248],{"class":3590},"coro = greet(",[3573,5250,5251],{"class":3638},"\"Іван\"",[3573,5253,3668],{"class":3590},[3573,5255,5256,5259,5261,5264,5267],{"class":3575,"line":3721},[3573,5257,5258],{"class":3608},"print",[3573,5260,3612],{"class":3590},[3573,5262,5263],{"class":3622},"type",[3573,5265,5266],{"class":3590},"(coro))                 ",[3573,5268,5269],{"class":3579},"# \u003Cclass 'coroutine'>\n",[3573,5271,5272],{"class":3575,"line":3727},[3573,5273,3598],{"emptyLinePlaceholder":3597},[3573,5275,5276],{"class":3575,"line":3816},[3573,5277,5278],{"class":3579},"# 2. Перевірка об'єкта та функції за допомогою inspect\n",[3573,5280,5281,5283,5286],{"class":3575,"line":3822},[3573,5282,5258],{"class":3608},[3573,5284,5285],{"class":3590},"(inspect.iscoroutinefunction(greet))  ",[3573,5287,5288],{"class":3579},"# True (сама функція)\n",[3573,5290,5291,5293,5296],{"class":3575,"line":3827},[3573,5292,5258],{"class":3608},[3573,5294,5295],{"class":3590},"(inspect.iscoroutine(coro))          ",[3573,5297,5298],{"class":3579},"# True (об'єкт, отриманий від виклику)\n",[3573,5300,5301,5303,5306],{"class":3575,"line":3833},[3573,5302,5258],{"class":3608},[3573,5304,5305],{"class":3590},"(inspect.isawaitable(coro))          ",[3573,5307,5308],{"class":3579},"# True (об'єкт підтримує протокол await)\n",[3573,5310,5311],{"class":3575,"line":3839},[3573,5312,3598],{"emptyLinePlaceholder":3597},[3573,5314,5315],{"class":3575,"line":3845},[3573,5316,5317],{"class":3579},"# 3. Для виконання корутини потрібен Event Loop.\n",[3573,5319,5320],{"class":3575,"line":3851},[3573,5321,5322],{"class":3579},"# asyncio.run() створює loop, реєструє корутину та запускає її.\n",[3573,5324,5325,5328,5331],{"class":3575,"line":3856},[3573,5326,5327],{"class":3590},"result = asyncio.run(greet(",[3573,5329,5330],{"class":3638},"\"Марія\"",[3573,5332,5333],{"class":3590},"))\n",[3573,5335,5336,5338,5341],{"class":3575,"line":3862},[3573,5337,5258],{"class":3608},[3573,5339,5340],{"class":3590},"(result)  ",[3573,5342,5343],{"class":3579},"# \"Привіт, Марія!\"\n",[3573,5345,5346],{"class":3575,"line":3868},[3573,5347,3598],{"emptyLinePlaceholder":3597},[3573,5349,5350],{"class":3575,"line":3874},[3573,5351,5352],{"class":3579},"# 4. Або ми викликаємо її зсередини іншої асинхронної функції через await:\n",[3573,5354,5355,5357,5359,5361],{"class":3575,"line":3880},[3573,5356,4005],{"class":3604},[3573,5358,4008],{"class":3604},[3573,5360,4161],{"class":3608},[3573,5362,5363],{"class":3590},"():\n",[3573,5365,5366,5369,5371,5374,5377,5379],{"class":3575,"line":3886},[3573,5367,5368],{"class":3590},"    result = ",[3573,5370,3488],{"class":3586},[3573,5372,5373],{"class":3590}," greet(",[3573,5375,5376],{"class":3638},"\"Олег\"",[3573,5378,4926],{"class":3590},[3573,5380,5381],{"class":3579},"# відновлення кадру корутини greet\n",[3573,5383,5384,5386],{"class":3575,"line":3891},[3573,5385,3645],{"class":3608},[3573,5387,5388],{"class":3590},"(result)\n",[3573,5390,5391],{"class":3575,"line":3897},[3573,5392,3598],{"emptyLinePlaceholder":3597},[3573,5394,5395],{"class":3575,"line":3902},[3573,5396,4193],{"class":3590},[4195,5398,5400,5408,5415,5421,5427,5431],{"title":5399},"python coroutine_anatomy.py",[4199,5401,5403],{"className":5402},[3575],[3573,5404,5407],{"className":5405},[5406],"text-blue-400","\u003Cclass 'coroutine'>",[4199,5409,5411],{"className":5410},[3575],[3573,5412,5414],{"className":5413},[5069],"True",[4199,5416,5418],{"className":5417},[3575],[3573,5419,5414],{"className":5420},[5069],[4199,5422,5424],{"className":5423},[3575],[3573,5425,5414],{"className":5426},[5069],[4199,5428,5430],{"className":5429},[3575],"Привіт, Марія!",[4199,5432,5434],{"className":5433},[3575],"Привіт, Олег!",[3458,5436],{},[3461,5438,5440],{"id":5439},"coroutine-vs-generator-схожість-і-відмінність","Coroutine vs Generator — схожість і відмінність",[3394,5442,5443,5444,5446,5447,3507],{},"Історично корутини в Python еволюціонували безпосередньо з генераторів (PEP 342, PEP 380, PEP 492). До версії Python 3.5 асинхронність реалізовувалася за допомогою генераторів, декорованих ",[3438,5445,3544],{},", де перемикання контексту здійснювалося через ",[3438,5448,3540],{},[3394,5450,5451,5452,5454],{},"Хоча сучасні рідні корутини (",[3438,5453,3553],{},") під капотом CPython все ще базуються на структурах генераторів, семантично та синтаксично це абсолютно різні сутності:",[5456,5457,5458,5479],"table",{},[5459,5460,5461],"thead",{},[5462,5463,5464,5469,5474],"tr",{},[5465,5466,5468],"th",{"align":5467},"left","Характеристика",[5465,5470,5471,5472,4290],{"align":5467},"Генератор (",[3438,5473,4330],{},[5465,5475,5476,5477,4290],{"align":5467},"Рідна корутина (",[3438,5478,3488],{},[5480,5481,5482,5500,5519,5536,5549,5566],"tbody",{},[5462,5483,5484,5490,5495],{},[5485,5486,5487],"td",{"align":5467},[3398,5488,5489],{},"Синтаксис оголошення",[5485,5491,5492],{"align":5467},[3438,5493,5494],{},"def f(): yield",[5485,5496,5497],{"align":5467},[3438,5498,5499],{},"async def f(): await",[5462,5501,5502,5507,5514],{},[5485,5503,5504],{"align":5467},[3398,5505,5506],{},"Основний інтерфейс",[5485,5508,5509,4369,5512],{"align":5467},[3438,5510,5511],{},"__next__()",[3438,5513,4368],{},[5485,5515,5516,5518],{"align":5467},[3438,5517,4302],{}," (повертає ітератор)",[5462,5520,5521,5526,5531],{},[5485,5522,5523],{"align":5467},[3398,5524,5525],{},"Повернення даних",[5485,5527,5528,5529],{"align":5467},"Багаторазове повернення значень через ",[3438,5530,4330],{},[5485,5532,5533,5534],{"align":5467},"Одне фінальне значення через ",[3438,5535,4398],{},[5462,5537,5538,5543,5546],{},[5485,5539,5540],{"align":5467},[3398,5541,5542],{},"Призначення",[5485,5544,5545],{"align":5467},"Лінива генерація послідовностей (data streams)",[5485,5547,5548],{"align":5467},"Неблокуюче очікування I\u002FO операцій",[5462,5550,5551,5556,5561],{},[5485,5552,5553],{"align":5467},[3398,5554,5555],{},"Сумісність з await",[5485,5557,5558,5559],{"align":5467},"Не можна викликати через ",[3438,5560,3488],{},[5485,5562,5563,5564],{"align":5467},"Можна очікувати через ",[3438,5565,3488],{},[5462,5567,5568,5573,5581],{},[5485,5569,5570],{"align":5467},[3398,5571,5572],{},"Життєвий цикл",[5485,5574,5575,5576,4369,5578],{"align":5467},"Керується вручну клієнтом через ",[3438,5577,4312],{},[3438,5579,5580],{},"for",[5485,5582,5583],{"align":5467},"Керується Event Loop через планувальник задач",[4267,5585,5587],{"id":5586},"асинхронні-генератори-pep-525","Асинхронні генератори (PEP 525)",[3394,5589,5590,5591,5132,5594,5597,5598,5600,5601,5603],{},"Поєднання концепції генератора та корутини дає ",[3398,5592,5593],{},"асинхронний генератор",[3438,5595,5596],{},"async generator","). Він створюється, коли всередині ",[3438,5599,3553],{}," використовується ключове слово ",[3438,5602,4330],{},". Асинхронний генератор дозволяє ліниво продукувати послідовності даних, роблячи асинхронні паузи між генерацією елементів (наприклад, при читанні рядків з асинхронного мережевого сокету):",[3564,5605,5607],{"className":3566,"code":5606,"language":3568,"meta":3569,"style":3569},"# coro_vs_gen.py\nimport asyncio\n\n# 1. Класичний генератор (виробник послідовності)\ndef fibonacci(limit: int):\n    a, b = 0, 1\n    for _ in range(limit):\n        yield a\n        a, b = b, a + b\n\n# 2. Асинхронна корутина (одноразова I\u002FO операція)\nasync def fetch_page(url: str) -> bytes:\n    await asyncio.sleep(0.1)   # симуляція асинхронного запиту\n    return b\"\u003Chtml>...\u003C\u002Fhtml>\" # повернення результату при завершенні\n\n# 3. Асинхронний генератор (поєднання обох концепцій)\nasync def async_range(n: int):\n    for i in range(n):\n        await asyncio.sleep(0.01)  # асинхронна пауза між значеннями\n        yield i                    # генерація елемента\n\nasync def consume_async_gen():\n    # Асинхронні генератори обходяться через конструкцію 'async for'\n    async for value in async_range(5):\n        print(value)\n",[3438,5608,5609,5614,5620,5624,5629,5648,5661,5675,5683,5688,5692,5697,5721,5734,5747,5751,5756,5776,5789,5802,5812,5816,5827,5832,5853],{"__ignoreMap":3569},[3573,5610,5611],{"class":3575,"line":3576},[3573,5612,5613],{"class":3579},"# coro_vs_gen.py\n",[3573,5615,5616,5618],{"class":3575,"line":3583},[3573,5617,3587],{"class":3586},[3573,5619,3591],{"class":3590},[3573,5621,5622],{"class":3575,"line":3594},[3573,5623,3598],{"emptyLinePlaceholder":3597},[3573,5625,5626],{"class":3575,"line":3601},[3573,5627,5628],{"class":3579},"# 1. Класичний генератор (виробник послідовності)\n",[3573,5630,5631,5633,5636,5638,5641,5643,5646],{"class":3575,"line":3635},[3573,5632,3605],{"class":3604},[3573,5634,5635],{"class":3608}," fibonacci",[3573,5637,3612],{"class":3590},[3573,5639,5640],{"class":3615},"limit",[3573,5642,3619],{"class":3590},[3573,5644,5645],{"class":3622},"int",[3573,5647,4108],{"class":3590},[3573,5649,5650,5653,5656,5658],{"class":3575,"line":3642},[3573,5651,5652],{"class":3590},"    a, b = ",[3573,5654,5655],{"class":4049},"0",[3573,5657,4890],{"class":3590},[3573,5659,5660],{"class":4049},"1\n",[3573,5662,5663,5665,5668,5670,5672],{"class":3575,"line":3671},[3573,5664,4091],{"class":3586},[3573,5666,5667],{"class":3590}," _ ",[3573,5669,4097],{"class":3586},[3573,5671,4100],{"class":3608},[3573,5673,5674],{"class":3590},"(limit):\n",[3573,5676,5677,5680],{"class":3575,"line":3676},[3573,5678,5679],{"class":3586},"        yield",[3573,5681,5682],{"class":3590}," a\n",[3573,5684,5685],{"class":3575,"line":3695},[3573,5686,5687],{"class":3590},"        a, b = b, a + b\n",[3573,5689,5690],{"class":3575,"line":3701},[3573,5691,3598],{"emptyLinePlaceholder":3597},[3573,5693,5694],{"class":3575,"line":3721},[3573,5695,5696],{"class":3579},"# 2. Асинхронна корутина (одноразова I\u002FO операція)\n",[3573,5698,5699,5701,5703,5706,5708,5711,5713,5715,5717,5719],{"class":3575,"line":3727},[3573,5700,4005],{"class":3604},[3573,5702,4008],{"class":3604},[3573,5704,5705],{"class":3608}," fetch_page",[3573,5707,3612],{"class":3590},[3573,5709,5710],{"class":3615},"url",[3573,5712,3619],{"class":3590},[3573,5714,4736],{"class":3622},[3573,5716,3626],{"class":3590},[3573,5718,3623],{"class":3622},[3573,5720,3632],{"class":3590},[3573,5722,5723,5725,5727,5729,5731],{"class":3575,"line":3816},[3573,5724,4043],{"class":3586},[3573,5726,4046],{"class":3590},[3573,5728,5213],{"class":4049},[3573,5730,4064],{"class":3590},[3573,5732,5733],{"class":3579},"# симуляція асинхронного запиту\n",[3573,5735,5736,5738,5741,5744],{"class":3575,"line":3822},[3573,5737,4759],{"class":3586},[3573,5739,5740],{"class":3604}," b",[3573,5742,5743],{"class":3638},"\"\u003Chtml>...\u003C\u002Fhtml>\"",[3573,5745,5746],{"class":3579}," # повернення результату при завершенні\n",[3573,5748,5749],{"class":3575,"line":3827},[3573,5750,3598],{"emptyLinePlaceholder":3597},[3573,5752,5753],{"class":3575,"line":3833},[3573,5754,5755],{"class":3579},"# 3. Асинхронний генератор (поєднання обох концепцій)\n",[3573,5757,5758,5760,5762,5765,5767,5770,5772,5774],{"class":3575,"line":3839},[3573,5759,4005],{"class":3604},[3573,5761,4008],{"class":3604},[3573,5763,5764],{"class":3608}," async_range",[3573,5766,3612],{"class":3590},[3573,5768,5769],{"class":3615},"n",[3573,5771,3619],{"class":3590},[3573,5773,5645],{"class":3622},[3573,5775,4108],{"class":3590},[3573,5777,5778,5780,5782,5784,5786],{"class":3575,"line":3845},[3573,5779,4091],{"class":3586},[3573,5781,4094],{"class":3590},[3573,5783,4097],{"class":3586},[3573,5785,4100],{"class":3608},[3573,5787,5788],{"class":3590},"(n):\n",[3573,5790,5791,5793,5795,5797,5799],{"class":3575,"line":3851},[3573,5792,4141],{"class":3586},[3573,5794,4046],{"class":3590},[3573,5796,4752],{"class":4049},[3573,5798,4926],{"class":3590},[3573,5800,5801],{"class":3579},"# асинхронна пауза між значеннями\n",[3573,5803,5804,5806,5809],{"class":3575,"line":3856},[3573,5805,5679],{"class":3586},[3573,5807,5808],{"class":3590}," i                    ",[3573,5810,5811],{"class":3579},"# генерація елемента\n",[3573,5813,5814],{"class":3575,"line":3862},[3573,5815,3598],{"emptyLinePlaceholder":3597},[3573,5817,5818,5820,5822,5825],{"class":3575,"line":3868},[3573,5819,4005],{"class":3604},[3573,5821,4008],{"class":3604},[3573,5823,5824],{"class":3608}," consume_async_gen",[3573,5826,5363],{"class":3590},[3573,5828,5829],{"class":3575,"line":3874},[3573,5830,5831],{"class":3579},"    # Асинхронні генератори обходяться через конструкцію 'async for'\n",[3573,5833,5834,5837,5840,5843,5845,5848,5851],{"class":3575,"line":3880},[3573,5835,5836],{"class":3586},"    async",[3573,5838,5839],{"class":3586}," for",[3573,5841,5842],{"class":3590}," value ",[3573,5844,4097],{"class":3586},[3573,5846,5847],{"class":3590}," async_range(",[3573,5849,5850],{"class":4049},"5",[3573,5852,4108],{"class":3590},[3573,5854,5855,5857],{"class":3575,"line":3886},[3573,5856,4113],{"class":3608},[3573,5858,5859],{"class":3590},"(value)\n",[3458,5861],{},[3461,5863,5865,5866,5868],{"id":5864},"що-можна-await-протокол-awaitable","Що можна ",[3438,5867,3488],{}," (Протокол Awaitable)",[3394,5870,5871,5872,5874,5875,5878,5879,5881],{},"Вираз ",[3438,5873,3488],{}," приймає лише ті об'єкти, які реалізують інтерфейс ",[3398,5876,5877],{},"Awaitable",". Об'єкт є awaitable, якщо у нього визначений магічний метод ",[3438,5880,4302],{},", який повертає ітератор.",[3394,5883,5884,5885,5887],{},"У стандартній бібліотеці ",[3438,5886,3451],{}," є три основні типи awaitable-об'єктів:",[5889,5890,5891,5899,5909],"field-group",{},[5892,5893,5895,5896,5898],"field",{"name":5894,"type":3553},"Корутина (Coroutine)","Об'єкт корутини, створений викликом асинхронної функції. Очікування корутини запускає її виконання безпосередньо в межах поточної задачі. Без ",[3438,5897,3488],{}," корутина просто висить у пам'яті як неактивний об'єкт.",[5892,5900,5902,5903,5905,5906,5908],{"name":5901,"type":4326},"Задача (Task)","Обгортка над корутиною, яка реєструє її в черзі Event Loop для негайного виконання. Створюється через ",[3438,5904,5089],{},". Задача починає виконуватися самостійно, навіть якщо ви її не очікуєте через ",[3438,5907,3488],{},". Очікування задачі повертає її результат або викликає виняток, якщо задача завершилась помилкою.",[5892,5910,5912,5913,4890,5916,4890,5919,5922],{"name":5911,"type":4323},"Ф'ючер (Future)","Низькорівневий об'єкт-контейнер, який представляє кінцевий результат асинхронної операції, що відбудеться в майбутньому. Має внутрішній стан (",[3438,5914,5915],{},"PENDING",[3438,5917,5918],{},"FINISHED",[3438,5920,5921],{},"CANCELLED","). Зазвичай розробники прикладного коду не створюють ф'ючери вручну; вони використовуються драйверами баз даних або бібліотеками зв'язку для інтеграції низькорівневих I\u002FO подій.",[3394,5924,5925],{},"Розглянемо практичну взаємодію з цими трьома категоріями awaitable-об'єктів:",[3564,5927,5929],{"className":3566,"code":5928,"language":3568,"meta":3569,"style":3569},"# awaitables_demo.py\nimport asyncio\n\nasync def compute() -> int:\n    await asyncio.sleep(0.1)\n    return 42\n\nasync def main():\n    # 1. Очікування корутини (послідовне виконання в поточному кадрі)\n    result = await compute()\n    print(f\"Coroutine: {result}\")\n\n    # 2. Очікування Task (корутина вже виконується у фоні Event Loop)\n    task = asyncio.create_task(compute())  # заплановано до виконання\n    print(\"Task створено і запущено у фоні Event Loop...\")\n    result = await task                    # очікуємо фінального результату\n    print(f\"Task result: {result}\")\n\n    # 3. Робота з низькорівневим Future\n    loop = asyncio.get_running_loop()\n    future: asyncio.Future[str] = loop.create_future()\n\n    # Встановимо результат вручну через callback в наступній ітерації циклу\n    loop.call_soon(future.set_result, \"future value\")\n\n    result = await future                  # очікування заповнення Future\n    print(f\"Future: {result}\")\n\nasyncio.run(main())\n",[3438,5930,5931,5936,5942,5946,5961,5971,5978,5982,5992,5997,6006,6028,6032,6037,6045,6056,6068,6089,6093,6098,6103,6113,6117,6122,6132,6136,6148,6169,6173],{"__ignoreMap":3569},[3573,5932,5933],{"class":3575,"line":3576},[3573,5934,5935],{"class":3579},"# awaitables_demo.py\n",[3573,5937,5938,5940],{"class":3575,"line":3583},[3573,5939,3587],{"class":3586},[3573,5941,3591],{"class":3590},[3573,5943,5944],{"class":3575,"line":3594},[3573,5945,3598],{"emptyLinePlaceholder":3597},[3573,5947,5948,5950,5952,5955,5957,5959],{"class":3575,"line":3601},[3573,5949,4005],{"class":3604},[3573,5951,4008],{"class":3604},[3573,5953,5954],{"class":3608}," compute",[3573,5956,4014],{"class":3590},[3573,5958,5645],{"class":3622},[3573,5960,3632],{"class":3590},[3573,5962,5963,5965,5967,5969],{"class":3575,"line":3635},[3573,5964,4043],{"class":3586},[3573,5966,4046],{"class":3590},[3573,5968,5213],{"class":4049},[3573,5970,3668],{"class":3590},[3573,5972,5973,5975],{"class":3575,"line":3642},[3573,5974,4759],{"class":3586},[3573,5976,5977],{"class":4049}," 42\n",[3573,5979,5980],{"class":3575,"line":3671},[3573,5981,3598],{"emptyLinePlaceholder":3597},[3573,5983,5984,5986,5988,5990],{"class":3575,"line":3676},[3573,5985,4005],{"class":3604},[3573,5987,4008],{"class":3604},[3573,5989,4161],{"class":3608},[3573,5991,5363],{"class":3590},[3573,5993,5994],{"class":3575,"line":3695},[3573,5995,5996],{"class":3579},"    # 1. Очікування корутини (послідовне виконання в поточному кадрі)\n",[3573,5998,5999,6001,6003],{"class":3575,"line":3701},[3573,6000,5368],{"class":3590},[3573,6002,3488],{"class":3586},[3573,6004,6005],{"class":3590}," compute()\n",[3573,6007,6008,6010,6012,6014,6017,6019,6022,6024,6026],{"class":3575,"line":3721},[3573,6009,3645],{"class":3608},[3573,6011,3612],{"class":3590},[3573,6013,3650],{"class":3604},[3573,6015,6016],{"class":3638},"\"Coroutine: ",[3573,6018,3656],{"class":3604},[3573,6020,6021],{"class":3590},"result",[3573,6023,3662],{"class":3604},[3573,6025,3665],{"class":3638},[3573,6027,3668],{"class":3590},[3573,6029,6030],{"class":3575,"line":3727},[3573,6031,3598],{"emptyLinePlaceholder":3597},[3573,6033,6034],{"class":3575,"line":3816},[3573,6035,6036],{"class":3579},"    # 2. Очікування Task (корутина вже виконується у фоні Event Loop)\n",[3573,6038,6039,6042],{"class":3575,"line":3822},[3573,6040,6041],{"class":3590},"    task = asyncio.create_task(compute())  ",[3573,6043,6044],{"class":3579},"# заплановано до виконання\n",[3573,6046,6047,6049,6051,6054],{"class":3575,"line":3827},[3573,6048,3645],{"class":3608},[3573,6050,3612],{"class":3590},[3573,6052,6053],{"class":3638},"\"Task створено і запущено у фоні Event Loop...\"",[3573,6055,3668],{"class":3590},[3573,6057,6058,6060,6062,6065],{"class":3575,"line":3833},[3573,6059,5368],{"class":3590},[3573,6061,3488],{"class":3586},[3573,6063,6064],{"class":3590}," task                    ",[3573,6066,6067],{"class":3579},"# очікуємо фінального результату\n",[3573,6069,6070,6072,6074,6076,6079,6081,6083,6085,6087],{"class":3575,"line":3839},[3573,6071,3645],{"class":3608},[3573,6073,3612],{"class":3590},[3573,6075,3650],{"class":3604},[3573,6077,6078],{"class":3638},"\"Task result: ",[3573,6080,3656],{"class":3604},[3573,6082,6021],{"class":3590},[3573,6084,3662],{"class":3604},[3573,6086,3665],{"class":3638},[3573,6088,3668],{"class":3590},[3573,6090,6091],{"class":3575,"line":3845},[3573,6092,3598],{"emptyLinePlaceholder":3597},[3573,6094,6095],{"class":3575,"line":3851},[3573,6096,6097],{"class":3579},"    # 3. Робота з низькорівневим Future\n",[3573,6099,6100],{"class":3575,"line":3856},[3573,6101,6102],{"class":3590},"    loop = asyncio.get_running_loop()\n",[3573,6104,6105,6108,6110],{"class":3575,"line":3862},[3573,6106,6107],{"class":3590},"    future: asyncio.Future[",[3573,6109,4736],{"class":3622},[3573,6111,6112],{"class":3590},"] = loop.create_future()\n",[3573,6114,6115],{"class":3575,"line":3868},[3573,6116,3598],{"emptyLinePlaceholder":3597},[3573,6118,6119],{"class":3575,"line":3874},[3573,6120,6121],{"class":3579},"    # Встановимо результат вручну через callback в наступній ітерації циклу\n",[3573,6123,6124,6127,6130],{"class":3575,"line":3880},[3573,6125,6126],{"class":3590},"    loop.call_soon(future.set_result, ",[3573,6128,6129],{"class":3638},"\"future value\"",[3573,6131,3668],{"class":3590},[3573,6133,6134],{"class":3575,"line":3886},[3573,6135,3598],{"emptyLinePlaceholder":3597},[3573,6137,6138,6140,6142,6145],{"class":3575,"line":3891},[3573,6139,5368],{"class":3590},[3573,6141,3488],{"class":3586},[3573,6143,6144],{"class":3590}," future                  ",[3573,6146,6147],{"class":3579},"# очікування заповнення Future\n",[3573,6149,6150,6152,6154,6156,6159,6161,6163,6165,6167],{"class":3575,"line":3897},[3573,6151,3645],{"class":3608},[3573,6153,3612],{"class":3590},[3573,6155,3650],{"class":3604},[3573,6157,6158],{"class":3638},"\"Future: ",[3573,6160,3656],{"class":3604},[3573,6162,6021],{"class":3590},[3573,6164,3662],{"class":3604},[3573,6166,3665],{"class":3638},[3573,6168,3668],{"class":3590},[3573,6170,6171],{"class":3575,"line":3902},[3573,6172,3598],{"emptyLinePlaceholder":3597},[3573,6174,6175],{"class":3575,"line":3908},[3573,6176,4193],{"class":3590},[3458,6178],{},[3461,6180,6182,6185],{"id":6181},"asynciorun-правильна-точка-входу",[3438,6183,6184],{},"asyncio.run()"," — правильна точка входу",[3394,6187,6188,6189,6191],{},"Починаючи з Python 3.7, функція ",[3438,6190,6184],{}," є стандартним та рекомендованим методом для запуску асинхронних програм. Вона повністю інкапсулює життєвий цикл Event Loop, автоматизуючи рутинні операції налаштування та завершення.",[3564,6193,6195],{"className":3566,"code":6194,"language":3568,"meta":3569,"style":3569},"# asyncio_run_usage.py\nimport asyncio\n\nasync def main() -> int:\n    print(\"Старт\")\n    await asyncio.sleep(0.1)\n    print(\"Фініш\")\n    return 0\n\n# ✅ Рекомендований сучасний підхід\nexit_code = asyncio.run(main())\n\n# ❌ Застарілий низькорівневий підхід (не використовуйте без потреби):\n# loop = asyncio.get_event_loop()\n# try:\n#     loop.run_until_complete(main())\n# finally:\n#     loop.close()\n",[3438,6196,6197,6202,6208,6212,6226,6237,6247,6258,6265,6269,6274,6279,6283,6288,6293,6298,6303,6308],{"__ignoreMap":3569},[3573,6198,6199],{"class":3575,"line":3576},[3573,6200,6201],{"class":3579},"# asyncio_run_usage.py\n",[3573,6203,6204,6206],{"class":3575,"line":3583},[3573,6205,3587],{"class":3586},[3573,6207,3591],{"class":3590},[3573,6209,6210],{"class":3575,"line":3594},[3573,6211,3598],{"emptyLinePlaceholder":3597},[3573,6213,6214,6216,6218,6220,6222,6224],{"class":3575,"line":3601},[3573,6215,4005],{"class":3604},[3573,6217,4008],{"class":3604},[3573,6219,4161],{"class":3608},[3573,6221,4014],{"class":3590},[3573,6223,5645],{"class":3622},[3573,6225,3632],{"class":3590},[3573,6227,6228,6230,6232,6235],{"class":3575,"line":3635},[3573,6229,3645],{"class":3608},[3573,6231,3612],{"class":3590},[3573,6233,6234],{"class":3638},"\"Старт\"",[3573,6236,3668],{"class":3590},[3573,6238,6239,6241,6243,6245],{"class":3575,"line":3642},[3573,6240,4043],{"class":3586},[3573,6242,4046],{"class":3590},[3573,6244,5213],{"class":4049},[3573,6246,3668],{"class":3590},[3573,6248,6249,6251,6253,6256],{"class":3575,"line":3671},[3573,6250,3645],{"class":3608},[3573,6252,3612],{"class":3590},[3573,6254,6255],{"class":3638},"\"Фініш\"",[3573,6257,3668],{"class":3590},[3573,6259,6260,6262],{"class":3575,"line":3676},[3573,6261,4759],{"class":3586},[3573,6263,6264],{"class":4049}," 0\n",[3573,6266,6267],{"class":3575,"line":3695},[3573,6268,3598],{"emptyLinePlaceholder":3597},[3573,6270,6271],{"class":3575,"line":3701},[3573,6272,6273],{"class":3579},"# ✅ Рекомендований сучасний підхід\n",[3573,6275,6276],{"class":3575,"line":3721},[3573,6277,6278],{"class":3590},"exit_code = asyncio.run(main())\n",[3573,6280,6281],{"class":3575,"line":3727},[3573,6282,3598],{"emptyLinePlaceholder":3597},[3573,6284,6285],{"class":3575,"line":3816},[3573,6286,6287],{"class":3579},"# ❌ Застарілий низькорівневий підхід (не використовуйте без потреби):\n",[3573,6289,6290],{"class":3575,"line":3822},[3573,6291,6292],{"class":3579},"# loop = asyncio.get_event_loop()\n",[3573,6294,6295],{"class":3575,"line":3827},[3573,6296,6297],{"class":3579},"# try:\n",[3573,6299,6300],{"class":3575,"line":3833},[3573,6301,6302],{"class":3579},"#     loop.run_until_complete(main())\n",[3573,6304,6305],{"class":3575,"line":3839},[3573,6306,6307],{"class":3579},"# finally:\n",[3573,6309,6310],{"class":3575,"line":3845},[3573,6311,6312],{"class":3579},"#     loop.close()\n",[4267,6314,6316,6317,6319],{"id":6315},"що-відбувається-під-капотом-asynciorun","Що відбувається під капотом ",[3438,6318,6184],{},"?",[3394,6321,6322,6323,4695],{},"Коли викликається ",[3438,6324,6325],{},"asyncio.run(coro)",[3422,6327,6328,6334,6340,6346,6364,6374],{},[3425,6329,6330,6333],{},[3398,6331,6332],{},"Створення циклу",": Функція створює новий екземпляр Event Loop (використовуючи поточну конфігурацію політики Event Loop Policy).",[3425,6335,6336,6339],{},[3398,6337,6338],{},"Встановлення контексту",": Вона реєструє створений цикл як поточний для активного потоку виконання.",[3425,6341,6342,6345],{},[3398,6343,6344],{},"Запуск корутини",": Виконує передану корутину до її повного завершення.",[3425,6347,6348,6351,6352,6355,6356,6359,6360,6363],{},[3398,6349,6350],{},"Очищення незавершених задач",": Після завершення головної корутини вона знаходить усі незавершені задачі (",[3438,6353,6354],{},"pending tasks","), скасовує їх через метод ",[3438,6357,6358],{},".cancel()"," та очікує їх завершення, обробляючи винятки ",[3438,6361,6362],{},"CancelledError",". Це запобігає «витоку» фонових задач.",[3425,6365,6366,6369,6370,6373],{},[3398,6367,6368],{},"Закриття асинхронних генераторів",": Викликає ",[3438,6371,6372],{},"loop.shutdown_asyncgens()"," для коректного закриття всіх активних асинхронних генераторів.",[3425,6375,6376,6379,6380,6383],{},[3398,6377,6378],{},"Закриття циклу",": Закриває Event Loop (",[3438,6381,6382],{},"loop.close()",") та скидає поточний подієвий цикл для потоку.",[6385,6386,6387,6389,6390,6392,6393,6396,6397,6400,6401,6404,6405,6408,6409,3507],"warning",{},[3438,6388,6184],{}," не можна викликати всередині потоку, де вже запущено інший Event Loop. Спроба викликати ",[3438,6391,6184],{}," призведе до помилки ",[3438,6394,6395],{},"RuntimeError: This event loop is already running",".\nЦе типова проблема при запуску асинхронного коду в інтерактивних середовищах типу ",[3398,6398,6399],{},"Jupyter Notebook"," або фреймворках на кшталт ",[3398,6402,6403],{},"Tornado\u002FTwisted",". У Jupyter Notebook подійний цикл запущений за замовчуванням, тому головну корутину потрібно запускати безпосередньо через ",[3438,6406,6407],{},"await main()"," або застосовувати сторонній пакет ",[3438,6410,6411],{},"nest_asyncio",[3458,6413],{},[3389,6415,6417,6418,4236,6421,6423],{"id":6416},"частина-iii-task-і-future-конкурентне-виконання","Частина III: ",[3438,6419,6420],{},"Task",[3438,6422,4337],{}," — конкурентне виконання",[3394,6425,6426,6427,6429,6430,6432,6433,3554,6435,6437],{},"Для побудови високопродуктивних додатків недостатньо просто викликати корутини послідовно через ",[3438,6428,3488],{},". Справжня сила асинхронності полягає в конкурентному виконанні завдань, коли кілька операцій очікують вводу-виводу одночасно. Для керування таким виконанням в ",[3438,6431,3451],{}," використовуються об'єкти ",[3438,6434,6420],{},[3438,6436,4337],{},", а також спеціальні допоміжні функції групування.",[3458,6439],{},[3461,6441,6443,6445],{"id":6442},"asynciocreate_task-планування-та-запуск-задачі",[3438,6444,5089],{}," — планування та запуск задачі",[3394,6447,6448,6449,6451,6452,6454,6455,6457],{},"Функція ",[3438,6450,5089],{}," є основним інструментом для переведення корутини в стан активного виконання. Вона обгортає об'єкт корутини в об'єкт ",[3438,6453,4326],{}," (який є підкласом ",[3438,6456,4323],{},") та негайно реєструє його в черзі виконання Event Loop.",[4267,6459,6461],{"id":6460},"сигнатура-функції","Сигнатура функції",[3564,6463,6465],{"className":3566,"code":6464,"language":3568,"meta":3569,"style":3569},"asyncio.create_task(coro, *, name=None, context=None)\n",[3438,6466,6467],{"__ignoreMap":3569},[3573,6468,6469,6472,6474,6477,6479,6481,6484,6486,6488],{"class":3575,"line":3576},[3573,6470,6471],{"class":3590},"asyncio.create_task(coro, *, ",[3573,6473,5194],{"class":3615},[3573,6475,6476],{"class":3590},"=",[3573,6478,3629],{"class":3604},[3573,6480,4890],{"class":3590},[3573,6482,6483],{"class":3615},"context",[3573,6485,6476],{"class":3590},[3573,6487,3629],{"class":3604},[3573,6489,3668],{"class":3590},[5889,6491,6492,6497,6507],{},[5892,6493,6496],{"name":6494,"type":6495},"coro","coroutine","Об'єкт корутини, який необхідно виконати.",[5892,6498,6500,6501,3554,6504,3507],{"name":5194,"type":6499,"default":3629},"str | None","Необов'язкове ім'я задачі (доступне з Python 3.8). Дозволяє ідентифікувати задачу при логуванні, налагодженні та отриманні імені через ",[3438,6502,6503],{},"task.get_name()",[3438,6505,6506],{},"task.set_name()",[5892,6508,6510,6511,3507],{"name":6483,"type":6509,"default":3629},"contextvars.Context | None","Контекст виконання задачі (доступно з Python 3.11). Дозволяє виконувати задачу у власному ізольованому контексті змінних ",[3438,6512,6513],{},"ContextVar",[4267,6515,6517],{"id":6516},"що-відбувається-під-капотом","Що відбувається під капотом?",[3422,6519,6520,6530,6547],{},[3425,6521,6522,3619,6525,6527,6528,3507],{},[3398,6523,6524],{},"Створення задачі",[3438,6526,5089],{}," викликає поточний Event Loop і створює об'єкт ",[3438,6529,6420],{},[3425,6531,6532,6535,6536,6539,6540,6543,6544,3507],{},[3398,6533,6534],{},"Чергування",": Loop реєструє крок виконання (",[3438,6537,6538],{},"Task.__step()",") у черзі готових завдань (",[3438,6541,6542],{},"Ready Queue",") за допомогою внутрішнього виклику типу ",[3438,6545,6546],{},"loop.call_soon()",[3425,6548,6549,6552,6553,6555],{},[3398,6550,6551],{},"Фонове виконання",": Задача починає виконуватися на наступній ітерації Event Loop, незалежно від того, чи було використано ключове слово ",[3438,6554,3488],{}," на самому об'єкті Task у поточному кадрі.",[3564,6557,6559],{"className":3566,"code":6558,"language":3568,"meta":3569,"style":3569},"# create_task_demo.py\nimport asyncio\nimport time\n\nasync def download(name: str, delay: float) -> str:\n    print(f\"[{name}] Починаю завантаження...\")\n    await asyncio.sleep(delay)\n    print(f\"[{name}] Готово! ({delay}s)\")\n    return f\"{name}: {delay}s\"\n\nasync def concurrent_with_tasks() -> None:\n    \"\"\"Конкурентне виконання через create_task.\"\"\"\n    t0 = time.perf_counter()\n\n    # create_task() планує виконання ОДРАЗУ — всі три завдання стартують конкурентно\n    task_a = asyncio.create_task(download(\"FileA\", 1.0), name=\"task-A\")\n    task_b = asyncio.create_task(download(\"FileB\", 1.5), name=\"task-B\")\n    task_c = asyncio.create_task(download(\"FileC\", 0.8), name=\"task-C\")\n\n    # Чекаємо результатів — оскільки задачі вже в черзі, вони виконуються паралельно\n    r1 = await task_a\n    r2 = await task_b\n    r3 = await task_c\n    print(f\"Concurrent: {time.perf_counter() - t0:.2f}s\")  # Обмежено найдовшим (~1.5s)\n\nasyncio.run(concurrent_with_tasks())\n",[3438,6560,6561,6566,6572,6578,6582,6615,6637,6644,6674,6699,6703,6718,6723,6727,6731,6736,6761,6785,6809,6813,6818,6827,6836,6846,6871,6875],{"__ignoreMap":3569},[3573,6562,6563],{"class":3575,"line":3576},[3573,6564,6565],{"class":3579},"# create_task_demo.py\n",[3573,6567,6568,6570],{"class":3575,"line":3583},[3573,6569,3587],{"class":3586},[3573,6571,3591],{"class":3590},[3573,6573,6574,6576],{"class":3575,"line":3594},[3573,6575,3587],{"class":3586},[3573,6577,4718],{"class":3590},[3573,6579,6580],{"class":3575,"line":3601},[3573,6581,3598],{"emptyLinePlaceholder":3597},[3573,6583,6584,6586,6588,6591,6593,6595,6597,6599,6601,6604,6606,6609,6611,6613],{"class":3575,"line":3635},[3573,6585,4005],{"class":3604},[3573,6587,4008],{"class":3604},[3573,6589,6590],{"class":3608}," download",[3573,6592,3612],{"class":3590},[3573,6594,5194],{"class":3615},[3573,6596,3619],{"class":3590},[3573,6598,4736],{"class":3622},[3573,6600,4890],{"class":3590},[3573,6602,6603],{"class":3615},"delay",[3573,6605,3619],{"class":3590},[3573,6607,6608],{"class":3622},"float",[3573,6610,3626],{"class":3590},[3573,6612,4736],{"class":3622},[3573,6614,3632],{"class":3590},[3573,6616,6617,6619,6621,6623,6626,6628,6630,6632,6635],{"class":3575,"line":3642},[3573,6618,3645],{"class":3608},[3573,6620,3612],{"class":3590},[3573,6622,3650],{"class":3604},[3573,6624,6625],{"class":3638},"\"[",[3573,6627,3656],{"class":3604},[3573,6629,5194],{"class":3590},[3573,6631,3662],{"class":3604},[3573,6633,6634],{"class":3638},"] Починаю завантаження...\"",[3573,6636,3668],{"class":3590},[3573,6638,6639,6641],{"class":3575,"line":3671},[3573,6640,4043],{"class":3586},[3573,6642,6643],{"class":3590}," asyncio.sleep(delay)\n",[3573,6645,6646,6648,6650,6652,6654,6656,6658,6660,6663,6665,6667,6669,6672],{"class":3575,"line":3676},[3573,6647,3645],{"class":3608},[3573,6649,3612],{"class":3590},[3573,6651,3650],{"class":3604},[3573,6653,6625],{"class":3638},[3573,6655,3656],{"class":3604},[3573,6657,5194],{"class":3590},[3573,6659,3662],{"class":3604},[3573,6661,6662],{"class":3638},"] Готово! (",[3573,6664,3656],{"class":3604},[3573,6666,6603],{"class":3590},[3573,6668,3662],{"class":3604},[3573,6670,6671],{"class":3638},"s)\"",[3573,6673,3668],{"class":3590},[3573,6675,6676,6678,6680,6682,6684,6686,6688,6690,6692,6694,6696],{"class":3575,"line":3695},[3573,6677,4759],{"class":3586},[3573,6679,5222],{"class":3604},[3573,6681,3665],{"class":3638},[3573,6683,3656],{"class":3604},[3573,6685,5194],{"class":3590},[3573,6687,3662],{"class":3604},[3573,6689,3619],{"class":3638},[3573,6691,3656],{"class":3604},[3573,6693,6603],{"class":3590},[3573,6695,3662],{"class":3604},[3573,6697,6698],{"class":3638},"s\"\n",[3573,6700,6701],{"class":3575,"line":3701},[3573,6702,3598],{"emptyLinePlaceholder":3597},[3573,6704,6705,6707,6709,6712,6714,6716],{"class":3575,"line":3721},[3573,6706,4005],{"class":3604},[3573,6708,4008],{"class":3604},[3573,6710,6711],{"class":3608}," concurrent_with_tasks",[3573,6713,4014],{"class":3590},[3573,6715,3629],{"class":3604},[3573,6717,3632],{"class":3590},[3573,6719,6720],{"class":3575,"line":3727},[3573,6721,6722],{"class":3638},"    \"\"\"Конкурентне виконання через create_task.\"\"\"\n",[3573,6724,6725],{"class":3575,"line":3816},[3573,6726,4839],{"class":3590},[3573,6728,6729],{"class":3575,"line":3822},[3573,6730,3598],{"emptyLinePlaceholder":3597},[3573,6732,6733],{"class":3575,"line":3827},[3573,6734,6735],{"class":3579},"    # create_task() планує виконання ОДРАЗУ — всі три завдання стартують конкурентно\n",[3573,6737,6738,6741,6744,6746,6749,6752,6754,6756,6759],{"class":3575,"line":3833},[3573,6739,6740],{"class":3590},"    task_a = asyncio.create_task(download(",[3573,6742,6743],{"class":3638},"\"FileA\"",[3573,6745,4890],{"class":3590},[3573,6747,6748],{"class":4049},"1.0",[3573,6750,6751],{"class":3590},"), ",[3573,6753,5194],{"class":3615},[3573,6755,6476],{"class":3590},[3573,6757,6758],{"class":3638},"\"task-A\"",[3573,6760,3668],{"class":3590},[3573,6762,6763,6766,6769,6771,6774,6776,6778,6780,6783],{"class":3575,"line":3839},[3573,6764,6765],{"class":3590},"    task_b = asyncio.create_task(download(",[3573,6767,6768],{"class":3638},"\"FileB\"",[3573,6770,4890],{"class":3590},[3573,6772,6773],{"class":4049},"1.5",[3573,6775,6751],{"class":3590},[3573,6777,5194],{"class":3615},[3573,6779,6476],{"class":3590},[3573,6781,6782],{"class":3638},"\"task-B\"",[3573,6784,3668],{"class":3590},[3573,6786,6787,6790,6793,6795,6798,6800,6802,6804,6807],{"class":3575,"line":3845},[3573,6788,6789],{"class":3590},"    task_c = asyncio.create_task(download(",[3573,6791,6792],{"class":3638},"\"FileC\"",[3573,6794,4890],{"class":3590},[3573,6796,6797],{"class":4049},"0.8",[3573,6799,6751],{"class":3590},[3573,6801,5194],{"class":3615},[3573,6803,6476],{"class":3590},[3573,6805,6806],{"class":3638},"\"task-C\"",[3573,6808,3668],{"class":3590},[3573,6810,6811],{"class":3575,"line":3851},[3573,6812,3598],{"emptyLinePlaceholder":3597},[3573,6814,6815],{"class":3575,"line":3856},[3573,6816,6817],{"class":3579},"    # Чекаємо результатів — оскільки задачі вже в черзі, вони виконуються паралельно\n",[3573,6819,6820,6822,6824],{"class":3575,"line":3862},[3573,6821,4849],{"class":3590},[3573,6823,3488],{"class":3586},[3573,6825,6826],{"class":3590}," task_a\n",[3573,6828,6829,6831,6833],{"class":3575,"line":3868},[3573,6830,4864],{"class":3590},[3573,6832,3488],{"class":3586},[3573,6834,6835],{"class":3590}," task_b\n",[3573,6837,6838,6841,6843],{"class":3575,"line":3874},[3573,6839,6840],{"class":3590},"    r3 = ",[3573,6842,3488],{"class":3586},[3573,6844,6845],{"class":3590}," task_c\n",[3573,6847,6848,6850,6852,6854,6857,6859,6861,6864,6866,6868],{"class":3575,"line":3880},[3573,6849,3645],{"class":3608},[3573,6851,3612],{"class":3590},[3573,6853,3650],{"class":3604},[3573,6855,6856],{"class":3638},"\"Concurrent: ",[3573,6858,3656],{"class":3604},[3573,6860,4917],{"class":3590},[3573,6862,6863],{"class":3604},":.2f}",[3573,6865,4923],{"class":3638},[3573,6867,4926],{"class":3590},[3573,6869,6870],{"class":3579},"# Обмежено найдовшим (~1.5s)\n",[3573,6872,6873],{"class":3575,"line":3886},[3573,6874,3598],{"emptyLinePlaceholder":3597},[3573,6876,6877],{"class":3575,"line":3891},[3573,6878,6879],{"class":3590},"asyncio.run(concurrent_with_tasks())\n",[4195,6881,6883,6887,6891,6895,6899,6903,6907],{"title":6882},"python create_task_demo.py",[4199,6884,6886],{"className":6885},[3575],"[FileA] Починаю завантаження...",[4199,6888,6890],{"className":6889},[3575],"[FileB] Починаю завантаження...",[4199,6892,6894],{"className":6893},[3575],"[FileC] Починаю завантаження...",[4199,6896,6898],{"className":6897},[3575],"[FileC] Готово! (0.8s)",[4199,6900,6902],{"className":6901},[3575],"[FileA] Готово! (1.0s)",[4199,6904,6906],{"className":6905},[3575],"[FileB] Готово! (1.5s)",[4199,6908,6910,6911,5048,6915],{"className":6909},[3575],"Concurrent: ",[3573,6912,6914],{"className":6913},[5069],"1.51s",[3573,6916,6918],{"className":6917},[4205],"← усі три стартували одночасно",[3458,6920],{},[3461,6922,6924,6926],{"id":6923},"asynciogather-конкурентне-агрегування-результатів",[3438,6925,4694],{}," — конкурентне агрегування результатів",[3394,6928,6448,6929,6931],{},[3438,6930,4694],{}," є високорівневим інструментом для одночасного запуску кількох awaitable-об'єктів та збору їхніх результатів в один упорядкований список.",[4267,6933,6461],{"id":6934},"сигнатура-функції-1",[3564,6936,6938],{"className":3566,"code":6937,"language":3568,"meta":3569,"style":3569},"asyncio.gather(*aws, return_exceptions=False)\n",[3438,6939,6940],{"__ignoreMap":3569},[3573,6941,6942,6945,6948,6950,6953],{"class":3575,"line":3576},[3573,6943,6944],{"class":3590},"asyncio.gather(*aws, ",[3573,6946,6947],{"class":3615},"return_exceptions",[3573,6949,6476],{"class":3590},[3573,6951,6952],{"class":3604},"False",[3573,6954,3668],{"class":3590},[5889,6956,6957,6962],{},[5892,6958,6961],{"name":6959,"type":6960},"\\*aws","tuple[Awaitable]","Послідовність awaitable-об'єктів (корутини автоматично обгортаються в Tasks).",[5892,6963,6965,6968],{"name":6947,"type":6964,"default":6952},"bool",[3394,6966,6967],{},"Визначає поведінку у випадку виникнення помилки в одній із задач:",[3936,6969,6970,6979],{},[3425,6971,6972,6974,6975,6978],{},[3438,6973,6952],{}," (за замовчуванням): перше ж виключення негайно перериває очікування і прокидається вгору до awaiter'а. При цьому інші задачі продовжують виконуватися у фоні Event Loop (вони ",[3398,6976,6977],{},"не скасовуються"," автоматично).",[3425,6980,6981,6983],{},[3438,6982,5414],{},": виключення не переривають виконання інших задач, а записуються у фінальний список результатів замість повернених значень.",[3564,6985,6987],{"className":3566,"code":6986,"language":3568,"meta":3569,"style":3569},"# gather_demo.py\nimport asyncio\n\nasync def fetch(url: str) -> tuple[str, int]:\n    await asyncio.sleep(0.3)   # симуляція мережевого запиту\n    return url, 200\n\nasync def main():\n    urls = [\n        \"https:\u002F\u002Fapi.example.com\u002Fusers\",\n        \"https:\u002F\u002Fapi.example.com\u002Fposts\",\n        \"https:\u002F\u002Fapi.example.com\u002Fcomments\",\n        \"https:\u002F\u002Fapi.example.com\u002Ftags\",\n    ]\n\n    # 1. Агрегування успішних результатів з розпакуванням\n    (url1, s1), (url2, s2), (url3, s3), (url4, s4) = await asyncio.gather(\n        *[fetch(u) for u in urls]\n    )\n    print(f\"Отримано {s1} від {url1}\")\n\n    # 2. Робота з помилками при return_exceptions=True\n    async def risky_fetch(url: str) -> str:\n        if \"bad\" in url:\n            raise ValueError(f\"Поганий URL: {url}\")\n        await asyncio.sleep(0.1)\n        return f\"OK: {url}\"\n\n    mixed_urls = [\"good\u002F1\", \"bad\u002Furl\", \"good\u002F2\"]\n    results = await asyncio.gather(\n        *[risky_fetch(u) for u in mixed_urls],\n        return_exceptions=True,   # перехоплює помилки та записує їх у список результатів\n    )\n    for url, result in zip(mixed_urls, results):\n        if isinstance(result, Exception):\n            print(f\"  ✗ {url}: {result}\")\n        else:\n            print(f\"  ✓ {url}: {result}\")\n\nasyncio.run(main())\n",[3438,6988,6989,6994,7000,7004,7033,7046,7056,7060,7070,7075,7083,7090,7097,7104,7109,7113,7118,7128,7143,7148,7180,7184,7189,7212,7226,7251,7261,7280,7284,7305,7314,7328,7343,7347,7362,7377,7407,7414,7443,7447],{"__ignoreMap":3569},[3573,6990,6991],{"class":3575,"line":3576},[3573,6992,6993],{"class":3579},"# gather_demo.py\n",[3573,6995,6996,6998],{"class":3575,"line":3583},[3573,6997,3587],{"class":3586},[3573,6999,3591],{"class":3590},[3573,7001,7002],{"class":3575,"line":3594},[3573,7003,3598],{"emptyLinePlaceholder":3597},[3573,7005,7006,7008,7010,7013,7015,7017,7019,7021,7024,7026,7028,7030],{"class":3575,"line":3601},[3573,7007,4005],{"class":3604},[3573,7009,4008],{"class":3604},[3573,7011,7012],{"class":3608}," fetch",[3573,7014,3612],{"class":3590},[3573,7016,5710],{"class":3615},[3573,7018,3619],{"class":3590},[3573,7020,4736],{"class":3622},[3573,7022,7023],{"class":3590},") -> tuple[",[3573,7025,4736],{"class":3622},[3573,7027,4890],{"class":3590},[3573,7029,5645],{"class":3622},[3573,7031,7032],{"class":3590},"]:\n",[3573,7034,7035,7037,7039,7041,7043],{"class":3575,"line":3635},[3573,7036,4043],{"class":3586},[3573,7038,4046],{"class":3590},[3573,7040,4146],{"class":4049},[3573,7042,4064],{"class":3590},[3573,7044,7045],{"class":3579},"# симуляція мережевого запиту\n",[3573,7047,7048,7050,7053],{"class":3575,"line":3642},[3573,7049,4759],{"class":3586},[3573,7051,7052],{"class":3590}," url, ",[3573,7054,7055],{"class":4049},"200\n",[3573,7057,7058],{"class":3575,"line":3671},[3573,7059,3598],{"emptyLinePlaceholder":3597},[3573,7061,7062,7064,7066,7068],{"class":3575,"line":3676},[3573,7063,4005],{"class":3604},[3573,7065,4008],{"class":3604},[3573,7067,4161],{"class":3608},[3573,7069,5363],{"class":3590},[3573,7071,7072],{"class":3575,"line":3695},[3573,7073,7074],{"class":3590},"    urls = [\n",[3573,7076,7077,7080],{"class":3575,"line":3701},[3573,7078,7079],{"class":3638},"        \"https:\u002F\u002Fapi.example.com\u002Fusers\"",[3573,7081,7082],{"class":3590},",\n",[3573,7084,7085,7088],{"class":3575,"line":3721},[3573,7086,7087],{"class":3638},"        \"https:\u002F\u002Fapi.example.com\u002Fposts\"",[3573,7089,7082],{"class":3590},[3573,7091,7092,7095],{"class":3575,"line":3727},[3573,7093,7094],{"class":3638},"        \"https:\u002F\u002Fapi.example.com\u002Fcomments\"",[3573,7096,7082],{"class":3590},[3573,7098,7099,7102],{"class":3575,"line":3816},[3573,7100,7101],{"class":3638},"        \"https:\u002F\u002Fapi.example.com\u002Ftags\"",[3573,7103,7082],{"class":3590},[3573,7105,7106],{"class":3575,"line":3822},[3573,7107,7108],{"class":3590},"    ]\n",[3573,7110,7111],{"class":3575,"line":3827},[3573,7112,3598],{"emptyLinePlaceholder":3597},[3573,7114,7115],{"class":3575,"line":3833},[3573,7116,7117],{"class":3579},"    # 1. Агрегування успішних результатів з розпакуванням\n",[3573,7119,7120,7123,7125],{"class":3575,"line":3839},[3573,7121,7122],{"class":3590},"    (url1, s1), (url2, s2), (url3, s3), (url4, s4) = ",[3573,7124,3488],{"class":3586},[3573,7126,7127],{"class":3590}," asyncio.gather(\n",[3573,7129,7130,7133,7135,7138,7140],{"class":3575,"line":3845},[3573,7131,7132],{"class":3590},"        *[fetch(u) ",[3573,7134,5580],{"class":3586},[3573,7136,7137],{"class":3590}," u ",[3573,7139,4097],{"class":3586},[3573,7141,7142],{"class":3590}," urls]\n",[3573,7144,7145],{"class":3575,"line":3851},[3573,7146,7147],{"class":3590},"    )\n",[3573,7149,7150,7152,7154,7156,7159,7161,7164,7166,7169,7171,7174,7176,7178],{"class":3575,"line":3856},[3573,7151,3645],{"class":3608},[3573,7153,3612],{"class":3590},[3573,7155,3650],{"class":3604},[3573,7157,7158],{"class":3638},"\"Отримано ",[3573,7160,3656],{"class":3604},[3573,7162,7163],{"class":3590},"s1",[3573,7165,3662],{"class":3604},[3573,7167,7168],{"class":3638}," від ",[3573,7170,3656],{"class":3604},[3573,7172,7173],{"class":3590},"url1",[3573,7175,3662],{"class":3604},[3573,7177,3665],{"class":3638},[3573,7179,3668],{"class":3590},[3573,7181,7182],{"class":3575,"line":3862},[3573,7183,3598],{"emptyLinePlaceholder":3597},[3573,7185,7186],{"class":3575,"line":3868},[3573,7187,7188],{"class":3579},"    # 2. Робота з помилками при return_exceptions=True\n",[3573,7190,7191,7193,7195,7198,7200,7202,7204,7206,7208,7210],{"class":3575,"line":3874},[3573,7192,5836],{"class":3604},[3573,7194,4008],{"class":3604},[3573,7196,7197],{"class":3608}," risky_fetch",[3573,7199,3612],{"class":3590},[3573,7201,5710],{"class":3615},[3573,7203,3619],{"class":3590},[3573,7205,4736],{"class":3622},[3573,7207,3626],{"class":3590},[3573,7209,4736],{"class":3622},[3573,7211,3632],{"class":3590},[3573,7213,7214,7217,7220,7223],{"class":3575,"line":3880},[3573,7215,7216],{"class":3586},"        if",[3573,7218,7219],{"class":3638}," \"bad\"",[3573,7221,7222],{"class":3604}," in",[3573,7224,7225],{"class":3590}," url:\n",[3573,7227,7228,7231,7234,7236,7238,7241,7243,7245,7247,7249],{"class":3575,"line":3886},[3573,7229,7230],{"class":3586},"            raise",[3573,7232,7233],{"class":3622}," ValueError",[3573,7235,3612],{"class":3590},[3573,7237,3650],{"class":3604},[3573,7239,7240],{"class":3638},"\"Поганий URL: ",[3573,7242,3656],{"class":3604},[3573,7244,5710],{"class":3590},[3573,7246,3662],{"class":3604},[3573,7248,3665],{"class":3638},[3573,7250,3668],{"class":3590},[3573,7252,7253,7255,7257,7259],{"class":3575,"line":3891},[3573,7254,4141],{"class":3586},[3573,7256,4046],{"class":3590},[3573,7258,5213],{"class":4049},[3573,7260,3668],{"class":3590},[3573,7262,7263,7266,7268,7271,7273,7275,7277],{"class":3575,"line":3897},[3573,7264,7265],{"class":3586},"        return",[3573,7267,5222],{"class":3604},[3573,7269,7270],{"class":3638},"\"OK: ",[3573,7272,3656],{"class":3604},[3573,7274,5710],{"class":3590},[3573,7276,3662],{"class":3604},[3573,7278,7279],{"class":3638},"\"\n",[3573,7281,7282],{"class":3575,"line":3902},[3573,7283,3598],{"emptyLinePlaceholder":3597},[3573,7285,7286,7289,7292,7294,7297,7299,7302],{"class":3575,"line":3908},[3573,7287,7288],{"class":3590},"    mixed_urls = [",[3573,7290,7291],{"class":3638},"\"good\u002F1\"",[3573,7293,4890],{"class":3590},[3573,7295,7296],{"class":3638},"\"bad\u002Furl\"",[3573,7298,4890],{"class":3590},[3573,7300,7301],{"class":3638},"\"good\u002F2\"",[3573,7303,7304],{"class":3590},"]\n",[3573,7306,7307,7310,7312],{"class":3575,"line":3913},[3573,7308,7309],{"class":3590},"    results = ",[3573,7311,3488],{"class":3586},[3573,7313,7127],{"class":3590},[3573,7315,7316,7319,7321,7323,7325],{"class":3575,"line":3919},[3573,7317,7318],{"class":3590},"        *[risky_fetch(u) ",[3573,7320,5580],{"class":3586},[3573,7322,7137],{"class":3590},[3573,7324,4097],{"class":3586},[3573,7326,7327],{"class":3590}," mixed_urls],\n",[3573,7329,7330,7333,7335,7337,7340],{"class":3575,"line":3925},[3573,7331,7332],{"class":3615},"        return_exceptions",[3573,7334,6476],{"class":3590},[3573,7336,5414],{"class":3604},[3573,7338,7339],{"class":3590},",   ",[3573,7341,7342],{"class":3579},"# перехоплює помилки та записує їх у список результатів\n",[3573,7344,7345],{"class":3575,"line":4576},[3573,7346,7147],{"class":3590},[3573,7348,7349,7351,7354,7356,7359],{"class":3575,"line":4582},[3573,7350,4091],{"class":3586},[3573,7352,7353],{"class":3590}," url, result ",[3573,7355,4097],{"class":3586},[3573,7357,7358],{"class":3608}," zip",[3573,7360,7361],{"class":3590},"(mixed_urls, results):\n",[3573,7363,7364,7366,7369,7372,7375],{"class":3575,"line":4588},[3573,7365,7216],{"class":3586},[3573,7367,7368],{"class":3608}," isinstance",[3573,7370,7371],{"class":3590},"(result, ",[3573,7373,7374],{"class":3622},"Exception",[3573,7376,4108],{"class":3590},[3573,7378,7379,7382,7384,7386,7389,7391,7393,7395,7397,7399,7401,7403,7405],{"class":3575,"line":4593},[3573,7380,7381],{"class":3608},"            print",[3573,7383,3612],{"class":3590},[3573,7385,3650],{"class":3604},[3573,7387,7388],{"class":3638},"\"  ✗ ",[3573,7390,3656],{"class":3604},[3573,7392,5710],{"class":3590},[3573,7394,3662],{"class":3604},[3573,7396,3619],{"class":3638},[3573,7398,3656],{"class":3604},[3573,7400,6021],{"class":3590},[3573,7402,3662],{"class":3604},[3573,7404,3665],{"class":3638},[3573,7406,3668],{"class":3590},[3573,7408,7409,7412],{"class":3575,"line":4599},[3573,7410,7411],{"class":3586},"        else",[3573,7413,3632],{"class":3590},[3573,7415,7416,7418,7420,7422,7425,7427,7429,7431,7433,7435,7437,7439,7441],{"class":3575,"line":4604},[3573,7417,7381],{"class":3608},[3573,7419,3612],{"class":3590},[3573,7421,3650],{"class":3604},[3573,7423,7424],{"class":3638},"\"  ✓ ",[3573,7426,3656],{"class":3604},[3573,7428,5710],{"class":3590},[3573,7430,3662],{"class":3604},[3573,7432,3619],{"class":3638},[3573,7434,3656],{"class":3604},[3573,7436,6021],{"class":3590},[3573,7438,3662],{"class":3604},[3573,7440,3665],{"class":3638},[3573,7442,3668],{"class":3590},[3573,7444,7445],{"class":3575,"line":4609},[3573,7446,3598],{"emptyLinePlaceholder":3597},[3573,7448,7449],{"class":3575,"line":4614},[3573,7450,4193],{"class":3590},[5076,7452,7453,7454,7456,7457,3507],{},"Хоча ",[3438,7455,4694],{}," є класичним API, він має певні недоліки з точки зору структурованої конкурентності: якщо одна задача падає з помилкою, інші продовжують роботу у «підвішеному» стані. Для створення надійного коду в сучасних версіях Python рекомендується використовувати ",[3438,7458,5093],{},[3458,7460],{},[3461,7462,7464,7467],{"id":7463},"asynciowait-тонке-керування-життєвим-циклом-групи-задач",[3438,7465,7466],{},"asyncio.wait()"," — тонке керування життєвим циклом групи задач",[3394,7469,7470,7471,7474,7475,7477,7478,7480,7481,7484,7485,7488],{},"На відміну від ",[3438,7472,7473],{},"gather()",", функція ",[3438,7476,7466],{}," не збирає результати безпосередньо. Вона повертає дві множини об'єктів ",[3438,7479,6420],{},": завершені (",[3438,7482,7483],{},"done",") та ті, що все ще виконуються (",[3438,7486,7487],{},"pending","). Це дозволяє створювати складні сценарії обробки (наприклад, реагувати на першу готову задачу або обмежувати час очікування).",[4267,7490,6461],{"id":7491},"сигнатура-функції-2",[3564,7493,7495],{"className":3566,"code":7494,"language":3568,"meta":3569,"style":3569},"asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)\n",[3438,7496,7497],{"__ignoreMap":3569},[3573,7498,7499,7502,7505,7507,7509,7511,7514],{"class":3575,"line":3576},[3573,7500,7501],{"class":3590},"asyncio.wait(aws, *, ",[3573,7503,7504],{"class":3615},"timeout",[3573,7506,6476],{"class":3590},[3573,7508,3629],{"class":3604},[3573,7510,4890],{"class":3590},[3573,7512,7513],{"class":3615},"return_when",[3573,7515,7516],{"class":3590},"=ALL_COMPLETED)\n",[5889,7518,7519,7534,7544],{},[5892,7520,7523,7524,7526,7527,7530,7531,3507],{"name":7521,"type":7522},"aws","Iterable[Task]","Колекція (множина чи список) об'єктів ",[3438,7525,6420],{},". Зверніть увагу: передача безпосередньо корутин (а не Task-об'єктів) у ",[3438,7528,7529],{},"wait()"," є застарілою поведінкою та викликає попередження ",[3438,7532,7533],{},"DeprecationWarning",[5892,7535,7537,7538,7540,7541,7543],{"name":7504,"type":7536,"default":3629},"float | int | None","Максимальний час очікування в секундах. Якщо час спливає, функція повертає поточний стан виконаних та незавершених задач. Задачі в ",[3438,7539,7487],{}," при цьому ",[3398,7542,6977],{}," автоматично.",[5892,7545,7547,7550],{"name":7513,"type":4736,"default":7546},"ALL_COMPLETED",[3394,7548,7549],{},"Умова повернення результатів:",[3936,7551,7552,7558,7564],{},[3425,7553,7554,7557],{},[3438,7555,7556],{},"FIRST_COMPLETED",": повертає керування, як тільки хоча б одна задача завершиться.",[3425,7559,7560,7563],{},[3438,7561,7562],{},"FIRST_EXCEPTION",": повертає керування, як тільки хоча б одна задача завершиться з помилкою (або коли всі задачі виконані успішно).",[3425,7565,7566,7568],{},[3438,7567,7546],{},": повертає керування лише після завершення всіх задач.",[3564,7570,7572],{"className":3566,"code":7571,"language":3568,"meta":3569,"style":3569},"# asyncio_wait_demo.py\nimport asyncio\n\nasync def task(name: str, delay: float) -> str:\n    await asyncio.sleep(delay)\n    return f\"{name} ({delay}s)\"\n\nasync def main():\n    tasks = {\n        asyncio.create_task(task(\"Alpha\",   0.5)),\n        asyncio.create_task(task(\"Beta\",    1.2)),\n        asyncio.create_task(task(\"Gamma\",   0.8)),\n        asyncio.create_task(task(\"Delta\",   2.0)),\n    }\n\n    # 1. Сценарій FIRST_COMPLETED (реакція на першу виконану задачу)\n    print(\"=== FIRST_COMPLETED ===\")\n    done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)\n    for t in done:\n        print(f\"  Перший завершений: {t.result()}\")\n    print(f\"  Ще виконуються (pending): {len(pending)} задач\")\n\n    # Скасування незавершених задач (найкраща практика)\n    for t in pending:\n        t.cancel()\n\n    # 2. Сценарій ALL_COMPLETED (очікування всіх задач)\n    tasks2 = {\n        asyncio.create_task(task(\"X\", 0.3)),\n        asyncio.create_task(task(\"Y\", 0.6)),\n    }\n    done2, pending2 = await asyncio.wait(tasks2, return_when=asyncio.ALL_COMPLETED)\n    for t in done2:\n        print(f\"  Результат: {t.result()}\")\n\n    # 3. Сценарій з таймаутом (очікування протягом обмеженого часу)\n    tasks3 = {asyncio.create_task(task(\"Slow\", 5.0))}\n    done3, pending3 = await asyncio.wait(tasks3, timeout=0.5)\n    if pending3:\n        print(f\"  Таймаут: {len(pending3)} задач не встигли завершитись\")\n        for t in pending3:\n            t.cancel()\n\nasyncio.run(main())\n",[3438,7573,7574,7579,7585,7589,7620,7626,7651,7655,7665,7670,7685,7700,7713,7727,7732,7736,7741,7752,7767,7779,7801,7827,7831,7836,7847,7852,7856,7861,7866,7879,7893,7897,7912,7923,7944,7948,7953,7969,7987,7995,8020,8031,8036,8040],{"__ignoreMap":3569},[3573,7575,7576],{"class":3575,"line":3576},[3573,7577,7578],{"class":3579},"# asyncio_wait_demo.py\n",[3573,7580,7581,7583],{"class":3575,"line":3583},[3573,7582,3587],{"class":3586},[3573,7584,3591],{"class":3590},[3573,7586,7587],{"class":3575,"line":3594},[3573,7588,3598],{"emptyLinePlaceholder":3597},[3573,7590,7591,7593,7595,7598,7600,7602,7604,7606,7608,7610,7612,7614,7616,7618],{"class":3575,"line":3601},[3573,7592,4005],{"class":3604},[3573,7594,4008],{"class":3604},[3573,7596,7597],{"class":3608}," task",[3573,7599,3612],{"class":3590},[3573,7601,5194],{"class":3615},[3573,7603,3619],{"class":3590},[3573,7605,4736],{"class":3622},[3573,7607,4890],{"class":3590},[3573,7609,6603],{"class":3615},[3573,7611,3619],{"class":3590},[3573,7613,6608],{"class":3622},[3573,7615,3626],{"class":3590},[3573,7617,4736],{"class":3622},[3573,7619,3632],{"class":3590},[3573,7621,7622,7624],{"class":3575,"line":3635},[3573,7623,4043],{"class":3586},[3573,7625,6643],{"class":3590},[3573,7627,7628,7630,7632,7634,7636,7638,7640,7642,7644,7646,7648],{"class":3575,"line":3642},[3573,7629,4759],{"class":3586},[3573,7631,5222],{"class":3604},[3573,7633,3665],{"class":3638},[3573,7635,3656],{"class":3604},[3573,7637,5194],{"class":3590},[3573,7639,3662],{"class":3604},[3573,7641,5132],{"class":3638},[3573,7643,3656],{"class":3604},[3573,7645,6603],{"class":3590},[3573,7647,3662],{"class":3604},[3573,7649,7650],{"class":3638},"s)\"\n",[3573,7652,7653],{"class":3575,"line":3671},[3573,7654,3598],{"emptyLinePlaceholder":3597},[3573,7656,7657,7659,7661,7663],{"class":3575,"line":3676},[3573,7658,4005],{"class":3604},[3573,7660,4008],{"class":3604},[3573,7662,4161],{"class":3608},[3573,7664,5363],{"class":3590},[3573,7666,7667],{"class":3575,"line":3695},[3573,7668,7669],{"class":3590},"    tasks = {\n",[3573,7671,7672,7675,7678,7680,7682],{"class":3575,"line":3701},[3573,7673,7674],{"class":3590},"        asyncio.create_task(task(",[3573,7676,7677],{"class":3638},"\"Alpha\"",[3573,7679,7339],{"class":3590},[3573,7681,4795],{"class":4049},[3573,7683,7684],{"class":3590},")),\n",[3573,7686,7687,7689,7692,7695,7698],{"class":3575,"line":3721},[3573,7688,7674],{"class":3590},[3573,7690,7691],{"class":3638},"\"Beta\"",[3573,7693,7694],{"class":3590},",    ",[3573,7696,7697],{"class":4049},"1.2",[3573,7699,7684],{"class":3590},[3573,7701,7702,7704,7707,7709,7711],{"class":3575,"line":3727},[3573,7703,7674],{"class":3590},[3573,7705,7706],{"class":3638},"\"Gamma\"",[3573,7708,7339],{"class":3590},[3573,7710,6797],{"class":4049},[3573,7712,7684],{"class":3590},[3573,7714,7715,7717,7720,7722,7725],{"class":3575,"line":3816},[3573,7716,7674],{"class":3590},[3573,7718,7719],{"class":3638},"\"Delta\"",[3573,7721,7339],{"class":3590},[3573,7723,7724],{"class":4049},"2.0",[3573,7726,7684],{"class":3590},[3573,7728,7729],{"class":3575,"line":3822},[3573,7730,7731],{"class":3590},"    }\n",[3573,7733,7734],{"class":3575,"line":3827},[3573,7735,3598],{"emptyLinePlaceholder":3597},[3573,7737,7738],{"class":3575,"line":3833},[3573,7739,7740],{"class":3579},"    # 1. Сценарій FIRST_COMPLETED (реакція на першу виконану задачу)\n",[3573,7742,7743,7745,7747,7750],{"class":3575,"line":3839},[3573,7744,3645],{"class":3608},[3573,7746,3612],{"class":3590},[3573,7748,7749],{"class":3638},"\"=== FIRST_COMPLETED ===\"",[3573,7751,3668],{"class":3590},[3573,7753,7754,7757,7759,7762,7764],{"class":3575,"line":3845},[3573,7755,7756],{"class":3590},"    done, pending = ",[3573,7758,3488],{"class":3586},[3573,7760,7761],{"class":3590}," asyncio.wait(tasks, ",[3573,7763,7513],{"class":3615},[3573,7765,7766],{"class":3590},"=asyncio.FIRST_COMPLETED)\n",[3573,7768,7769,7771,7774,7776],{"class":3575,"line":3851},[3573,7770,4091],{"class":3586},[3573,7772,7773],{"class":3590}," t ",[3573,7775,4097],{"class":3586},[3573,7777,7778],{"class":3590}," done:\n",[3573,7780,7781,7783,7785,7787,7790,7792,7795,7797,7799],{"class":3575,"line":3856},[3573,7782,4113],{"class":3608},[3573,7784,3612],{"class":3590},[3573,7786,3650],{"class":3604},[3573,7788,7789],{"class":3638},"\"  Перший завершений: ",[3573,7791,3656],{"class":3604},[3573,7793,7794],{"class":3590},"t.result()",[3573,7796,3662],{"class":3604},[3573,7798,3665],{"class":3638},[3573,7800,3668],{"class":3590},[3573,7802,7803,7805,7807,7809,7812,7814,7817,7820,7822,7825],{"class":3575,"line":3862},[3573,7804,3645],{"class":3608},[3573,7806,3612],{"class":3590},[3573,7808,3650],{"class":3604},[3573,7810,7811],{"class":3638},"\"  Ще виконуються (pending): ",[3573,7813,3656],{"class":3604},[3573,7815,7816],{"class":3608},"len",[3573,7818,7819],{"class":3590},"(pending)",[3573,7821,3662],{"class":3604},[3573,7823,7824],{"class":3638}," задач\"",[3573,7826,3668],{"class":3590},[3573,7828,7829],{"class":3575,"line":3868},[3573,7830,3598],{"emptyLinePlaceholder":3597},[3573,7832,7833],{"class":3575,"line":3874},[3573,7834,7835],{"class":3579},"    # Скасування незавершених задач (найкраща практика)\n",[3573,7837,7838,7840,7842,7844],{"class":3575,"line":3880},[3573,7839,4091],{"class":3586},[3573,7841,7773],{"class":3590},[3573,7843,4097],{"class":3586},[3573,7845,7846],{"class":3590}," pending:\n",[3573,7848,7849],{"class":3575,"line":3886},[3573,7850,7851],{"class":3590},"        t.cancel()\n",[3573,7853,7854],{"class":3575,"line":3891},[3573,7855,3598],{"emptyLinePlaceholder":3597},[3573,7857,7858],{"class":3575,"line":3897},[3573,7859,7860],{"class":3579},"    # 2. Сценарій ALL_COMPLETED (очікування всіх задач)\n",[3573,7862,7863],{"class":3575,"line":3902},[3573,7864,7865],{"class":3590},"    tasks2 = {\n",[3573,7867,7868,7870,7873,7875,7877],{"class":3575,"line":3908},[3573,7869,7674],{"class":3590},[3573,7871,7872],{"class":3638},"\"X\"",[3573,7874,4890],{"class":3590},[3573,7876,4146],{"class":4049},[3573,7878,7684],{"class":3590},[3573,7880,7881,7883,7886,7888,7891],{"class":3575,"line":3913},[3573,7882,7674],{"class":3590},[3573,7884,7885],{"class":3638},"\"Y\"",[3573,7887,4890],{"class":3590},[3573,7889,7890],{"class":4049},"0.6",[3573,7892,7684],{"class":3590},[3573,7894,7895],{"class":3575,"line":3919},[3573,7896,7731],{"class":3590},[3573,7898,7899,7902,7904,7907,7909],{"class":3575,"line":3925},[3573,7900,7901],{"class":3590},"    done2, pending2 = ",[3573,7903,3488],{"class":3586},[3573,7905,7906],{"class":3590}," asyncio.wait(tasks2, ",[3573,7908,7513],{"class":3615},[3573,7910,7911],{"class":3590},"=asyncio.ALL_COMPLETED)\n",[3573,7913,7914,7916,7918,7920],{"class":3575,"line":4576},[3573,7915,4091],{"class":3586},[3573,7917,7773],{"class":3590},[3573,7919,4097],{"class":3586},[3573,7921,7922],{"class":3590}," done2:\n",[3573,7924,7925,7927,7929,7931,7934,7936,7938,7940,7942],{"class":3575,"line":4582},[3573,7926,4113],{"class":3608},[3573,7928,3612],{"class":3590},[3573,7930,3650],{"class":3604},[3573,7932,7933],{"class":3638},"\"  Результат: ",[3573,7935,3656],{"class":3604},[3573,7937,7794],{"class":3590},[3573,7939,3662],{"class":3604},[3573,7941,3665],{"class":3638},[3573,7943,3668],{"class":3590},[3573,7945,7946],{"class":3575,"line":4588},[3573,7947,3598],{"emptyLinePlaceholder":3597},[3573,7949,7950],{"class":3575,"line":4593},[3573,7951,7952],{"class":3579},"    # 3. Сценарій з таймаутом (очікування протягом обмеженого часу)\n",[3573,7954,7955,7958,7961,7963,7966],{"class":3575,"line":4599},[3573,7956,7957],{"class":3590},"    tasks3 = {asyncio.create_task(task(",[3573,7959,7960],{"class":3638},"\"Slow\"",[3573,7962,4890],{"class":3590},[3573,7964,7965],{"class":4049},"5.0",[3573,7967,7968],{"class":3590},"))}\n",[3573,7970,7971,7974,7976,7979,7981,7983,7985],{"class":3575,"line":4604},[3573,7972,7973],{"class":3590},"    done3, pending3 = ",[3573,7975,3488],{"class":3586},[3573,7977,7978],{"class":3590}," asyncio.wait(tasks3, ",[3573,7980,7504],{"class":3615},[3573,7982,6476],{"class":3590},[3573,7984,4795],{"class":4049},[3573,7986,3668],{"class":3590},[3573,7988,7989,7992],{"class":3575,"line":4609},[3573,7990,7991],{"class":3586},"    if",[3573,7993,7994],{"class":3590}," pending3:\n",[3573,7996,7997,7999,8001,8003,8006,8008,8010,8013,8015,8018],{"class":3575,"line":4614},[3573,7998,4113],{"class":3608},[3573,8000,3612],{"class":3590},[3573,8002,3650],{"class":3604},[3573,8004,8005],{"class":3638},"\"  Таймаут: ",[3573,8007,3656],{"class":3604},[3573,8009,7816],{"class":3608},[3573,8011,8012],{"class":3590},"(pending3)",[3573,8014,3662],{"class":3604},[3573,8016,8017],{"class":3638}," задач не встигли завершитись\"",[3573,8019,3668],{"class":3590},[3573,8021,8022,8025,8027,8029],{"class":3575,"line":4620},[3573,8023,8024],{"class":3586},"        for",[3573,8026,7773],{"class":3590},[3573,8028,4097],{"class":3586},[3573,8030,7994],{"class":3590},[3573,8032,8033],{"class":3575,"line":4626},[3573,8034,8035],{"class":3590},"            t.cancel()\n",[3573,8037,8038],{"class":3575,"line":4631},[3573,8039,3598],{"emptyLinePlaceholder":3597},[3573,8041,8042],{"class":3575,"line":4636},[3573,8043,4193],{"class":3590},[3458,8045],{},[3461,8047,8049,8052],{"id":8048},"asyncioas_completed-обробка-результатів-по-мірі-готовності",[3438,8050,8051],{},"asyncio.as_completed()"," — обробка результатів по мірі готовності",[3394,8054,6448,8055,8057,8058,8060],{},[3438,8056,8051],{}," повертає генератор (ітератор), який на кожному кроці видає ",[3438,8059,4337],{},"-об'єкт, що завершується наступним за чергою. Це дає змогу обробляти результати задач одразу по мірі їх виконання, мінімізуючи затримки.",[4267,8062,6461],{"id":8063},"сигнатура-функції-3",[3564,8065,8067],{"className":3566,"code":8066,"language":3568,"meta":3569,"style":3569},"asyncio.as_completed(aws, *, timeout=None)\n",[3438,8068,8069],{"__ignoreMap":3569},[3573,8070,8071,8074,8076,8078,8080],{"class":3575,"line":3576},[3573,8072,8073],{"class":3590},"asyncio.as_completed(aws, *, ",[3573,8075,7504],{"class":3615},[3573,8077,6476],{"class":3590},[3573,8079,3629],{"class":3604},[3573,8081,3668],{"class":3590},[8083,8084,8085,8086,8089,8090,8092,8093,8096,8097,8099,8100,8102,8103,3507],"note",{},"Помилкою багатьох початківців є використання конструкції ",[3438,8087,8088],{},"async for"," із цією функцією. ",[3438,8091,8051],{}," повертає ",[3398,8094,8095],{},"звичайний синхронний ітератор"," (генератор), який видає асинхронні ",[3438,8098,4337],{},". Тому обхід має здійснюватися через класичний цикл ",[3438,8101,5580],{},", а вже елемент, який він повертає, очікується через ",[3438,8104,3488],{},[3564,8106,8108],{"className":3566,"code":8107,"language":3568,"meta":3569,"style":3569},"# as_completed_demo.py\nimport asyncio\nimport random\n\nasync def fetch_random(item_id: int) -> tuple[int, float]:\n    delay = random.uniform(0.1, 1.0)\n    await asyncio.sleep(delay)\n    return item_id, delay\n\nasync def main():\n    tasks = [fetch_random(i) for i in range(10)]\n\n    print(\"Результати в порядку завершення:\")\n    # Використовуємо звичайний 'for' для обходу ітератора, але 'await' для отримання результату\n    for coro_future in asyncio.as_completed(tasks):\n        item_id, delay = await coro_future\n        print(f\"  #{item_id:02d} завершено за {delay:.2f}s\")\n\nasyncio.run(main())\n",[3438,8109,8110,8115,8121,8128,8132,8160,8173,8179,8186,8190,8200,8221,8225,8236,8241,8253,8263,8294,8298],{"__ignoreMap":3569},[3573,8111,8112],{"class":3575,"line":3576},[3573,8113,8114],{"class":3579},"# as_completed_demo.py\n",[3573,8116,8117,8119],{"class":3575,"line":3583},[3573,8118,3587],{"class":3586},[3573,8120,3591],{"class":3590},[3573,8122,8123,8125],{"class":3575,"line":3594},[3573,8124,3587],{"class":3586},[3573,8126,8127],{"class":3590}," random\n",[3573,8129,8130],{"class":3575,"line":3601},[3573,8131,3598],{"emptyLinePlaceholder":3597},[3573,8133,8134,8136,8138,8141,8143,8146,8148,8150,8152,8154,8156,8158],{"class":3575,"line":3635},[3573,8135,4005],{"class":3604},[3573,8137,4008],{"class":3604},[3573,8139,8140],{"class":3608}," fetch_random",[3573,8142,3612],{"class":3590},[3573,8144,8145],{"class":3615},"item_id",[3573,8147,3619],{"class":3590},[3573,8149,5645],{"class":3622},[3573,8151,7023],{"class":3590},[3573,8153,5645],{"class":3622},[3573,8155,4890],{"class":3590},[3573,8157,6608],{"class":3622},[3573,8159,7032],{"class":3590},[3573,8161,8162,8165,8167,8169,8171],{"class":3575,"line":3642},[3573,8163,8164],{"class":3590},"    delay = random.uniform(",[3573,8166,5213],{"class":4049},[3573,8168,4890],{"class":3590},[3573,8170,6748],{"class":4049},[3573,8172,3668],{"class":3590},[3573,8174,8175,8177],{"class":3575,"line":3671},[3573,8176,4043],{"class":3586},[3573,8178,6643],{"class":3590},[3573,8180,8181,8183],{"class":3575,"line":3676},[3573,8182,4759],{"class":3586},[3573,8184,8185],{"class":3590}," item_id, delay\n",[3573,8187,8188],{"class":3575,"line":3695},[3573,8189,3598],{"emptyLinePlaceholder":3597},[3573,8191,8192,8194,8196,8198],{"class":3575,"line":3701},[3573,8193,4005],{"class":3604},[3573,8195,4008],{"class":3604},[3573,8197,4161],{"class":3608},[3573,8199,5363],{"class":3590},[3573,8201,8202,8205,8207,8209,8211,8213,8215,8218],{"class":3575,"line":3721},[3573,8203,8204],{"class":3590},"    tasks = [fetch_random(i) ",[3573,8206,5580],{"class":3586},[3573,8208,4094],{"class":3590},[3573,8210,4097],{"class":3586},[3573,8212,4100],{"class":3608},[3573,8214,3612],{"class":3590},[3573,8216,8217],{"class":4049},"10",[3573,8219,8220],{"class":3590},")]\n",[3573,8222,8223],{"class":3575,"line":3727},[3573,8224,3598],{"emptyLinePlaceholder":3597},[3573,8226,8227,8229,8231,8234],{"class":3575,"line":3816},[3573,8228,3645],{"class":3608},[3573,8230,3612],{"class":3590},[3573,8232,8233],{"class":3638},"\"Результати в порядку завершення:\"",[3573,8235,3668],{"class":3590},[3573,8237,8238],{"class":3575,"line":3822},[3573,8239,8240],{"class":3579},"    # Використовуємо звичайний 'for' для обходу ітератора, але 'await' для отримання результату\n",[3573,8242,8243,8245,8248,8250],{"class":3575,"line":3827},[3573,8244,4091],{"class":3586},[3573,8246,8247],{"class":3590}," coro_future ",[3573,8249,4097],{"class":3586},[3573,8251,8252],{"class":3590}," asyncio.as_completed(tasks):\n",[3573,8254,8255,8258,8260],{"class":3575,"line":3833},[3573,8256,8257],{"class":3590},"        item_id, delay = ",[3573,8259,3488],{"class":3586},[3573,8261,8262],{"class":3590}," coro_future\n",[3573,8264,8265,8267,8269,8271,8274,8276,8278,8281,8284,8286,8288,8290,8292],{"class":3575,"line":3839},[3573,8266,4113],{"class":3608},[3573,8268,3612],{"class":3590},[3573,8270,3650],{"class":3604},[3573,8272,8273],{"class":3638},"\"  #",[3573,8275,3656],{"class":3604},[3573,8277,8145],{"class":3590},[3573,8279,8280],{"class":3604},":02d}",[3573,8282,8283],{"class":3638}," завершено за ",[3573,8285,3656],{"class":3604},[3573,8287,6603],{"class":3590},[3573,8289,6863],{"class":3604},[3573,8291,4923],{"class":3638},[3573,8293,3668],{"class":3590},[3573,8295,8296],{"class":3575,"line":3845},[3573,8297,3598],{"emptyLinePlaceholder":3597},[3573,8299,8300],{"class":3575,"line":3851},[3573,8301,4193],{"class":3590},[3458,8303],{},[3461,8305,8307,8309],{"id":8306},"asynciotaskgroup-структурована-конкурентність-python-311",[3438,8308,5093],{}," — структурована конкурентність (Python 3.11+)",[3394,8311,8312,8313,8315,8316,8321,8322,8325],{},"Починаючи з версії Python 3.11, концепція конкурентного виконання в ",[3438,8314,3451],{}," отримала значне оновлення у вигляді ",[3398,8317,8318],{},[3438,8319,8320],{},"TaskGroup",". Це асинхронний контекстний менеджер, який реалізує принципи ",[3398,8323,8324],{},"структурованої конкурентності"," (Structured Concurrency).",[4267,8327,8329,8330,8332],{"id":8328},"чому-taskgroup-є-сучасним-стандартом","Чому ",[3438,8331,8320],{}," є сучасним стандартом?",[3422,8334,8335,8344,8354],{},[3425,8336,8337,8340,8341,8343],{},[3398,8338,8339],{},"Безпека скасування",": Якщо будь-яка задача всередині ",[3438,8342,8320],{}," завершується з помилкою (кидає виключення), менеджер контексту автоматично скасовує всі інші активні задачі цієї групи.",[3425,8345,8346,8349,8350,8353],{},[3398,8347,8348],{},"Гарантія завершення",": При виході з блоку ",[3438,8351,8352],{},"async with"," гарантується, що всі задачі групи або завершилися успішно, або були скасовані, або завершилися помилкою. Виключається поява «загублених» фонових задач.",[3425,8355,8356,8359,8360,8363,8364,3507],{},[3398,8357,8358],{},"ExceptionGroup (PEP 654)",": Якщо в групі виникає кілька помилок одночасно, вони групуються у спеціальний виняток ",[3438,8361,8362],{},"ExceptionGroup",". Їх можна перехоплювати за допомогою нового синтаксису ",[3438,8365,8366],{},"except*",[3564,8368,8370],{"className":3566,"code":8369,"language":3568,"meta":3569,"style":3569},"# task_group_demo.py\nimport asyncio\n\nasync def worker(name: str, delay: float) -> str:\n    await asyncio.sleep(delay)\n    print(f\"  [Worker {name}] done\")\n    return name\n\nasync def main():\n    try:\n        # Усі задачі всередині групи виконуються паралельно\n        async with asyncio.TaskGroup() as tg:\n            t1 = tg.create_task(worker(\"A\", 0.3))\n            t2 = tg.create_task(worker(\"B\", 0.5))\n            t3 = tg.create_task(worker(\"C\", 0.8))\n\n        # Вихід із блоку async with можливий ТІЛЬКИ після завершення всіх задач групи\n        print(f\"Результати: {t1.result()}, {t2.result()}, {t3.result()}\")\n    except* ValueError as eg:\n        # Перехоплення кількох потенційних ValueError за допомогою except*\n        print(f\"Виявлено помилки у TaskGroup: {eg.exceptions}\")\n\nasyncio.run(main())\n",[3438,8371,8372,8377,8383,8387,8418,8424,8446,8453,8457,8467,8474,8479,8496,8510,8524,8538,8542,8547,8586,8603,8608,8630,8634],{"__ignoreMap":3569},[3573,8373,8374],{"class":3575,"line":3576},[3573,8375,8376],{"class":3579},"# task_group_demo.py\n",[3573,8378,8379,8381],{"class":3575,"line":3583},[3573,8380,3587],{"class":3586},[3573,8382,3591],{"class":3590},[3573,8384,8385],{"class":3575,"line":3594},[3573,8386,3598],{"emptyLinePlaceholder":3597},[3573,8388,8389,8391,8393,8396,8398,8400,8402,8404,8406,8408,8410,8412,8414,8416],{"class":3575,"line":3601},[3573,8390,4005],{"class":3604},[3573,8392,4008],{"class":3604},[3573,8394,8395],{"class":3608}," worker",[3573,8397,3612],{"class":3590},[3573,8399,5194],{"class":3615},[3573,8401,3619],{"class":3590},[3573,8403,4736],{"class":3622},[3573,8405,4890],{"class":3590},[3573,8407,6603],{"class":3615},[3573,8409,3619],{"class":3590},[3573,8411,6608],{"class":3622},[3573,8413,3626],{"class":3590},[3573,8415,4736],{"class":3622},[3573,8417,3632],{"class":3590},[3573,8419,8420,8422],{"class":3575,"line":3635},[3573,8421,4043],{"class":3586},[3573,8423,6643],{"class":3590},[3573,8425,8426,8428,8430,8432,8435,8437,8439,8441,8444],{"class":3575,"line":3642},[3573,8427,3645],{"class":3608},[3573,8429,3612],{"class":3590},[3573,8431,3650],{"class":3604},[3573,8433,8434],{"class":3638},"\"  [Worker ",[3573,8436,3656],{"class":3604},[3573,8438,5194],{"class":3590},[3573,8440,3662],{"class":3604},[3573,8442,8443],{"class":3638},"] done\"",[3573,8445,3668],{"class":3590},[3573,8447,8448,8450],{"class":3575,"line":3671},[3573,8449,4759],{"class":3586},[3573,8451,8452],{"class":3590}," name\n",[3573,8454,8455],{"class":3575,"line":3676},[3573,8456,3598],{"emptyLinePlaceholder":3597},[3573,8458,8459,8461,8463,8465],{"class":3575,"line":3695},[3573,8460,4005],{"class":3604},[3573,8462,4008],{"class":3604},[3573,8464,4161],{"class":3608},[3573,8466,5363],{"class":3590},[3573,8468,8469,8472],{"class":3575,"line":3701},[3573,8470,8471],{"class":3586},"    try",[3573,8473,3632],{"class":3590},[3573,8475,8476],{"class":3575,"line":3721},[3573,8477,8478],{"class":3579},"        # Усі задачі всередині групи виконуються паралельно\n",[3573,8480,8481,8484,8487,8490,8493],{"class":3575,"line":3727},[3573,8482,8483],{"class":3586},"        async",[3573,8485,8486],{"class":3586}," with",[3573,8488,8489],{"class":3590}," asyncio.TaskGroup() ",[3573,8491,8492],{"class":3586},"as",[3573,8494,8495],{"class":3590}," tg:\n",[3573,8497,8498,8501,8504,8506,8508],{"class":3575,"line":3816},[3573,8499,8500],{"class":3590},"            t1 = tg.create_task(worker(",[3573,8502,8503],{"class":3638},"\"A\"",[3573,8505,4890],{"class":3590},[3573,8507,4146],{"class":4049},[3573,8509,5333],{"class":3590},[3573,8511,8512,8515,8518,8520,8522],{"class":3575,"line":3822},[3573,8513,8514],{"class":3590},"            t2 = tg.create_task(worker(",[3573,8516,8517],{"class":3638},"\"B\"",[3573,8519,4890],{"class":3590},[3573,8521,4795],{"class":4049},[3573,8523,5333],{"class":3590},[3573,8525,8526,8529,8532,8534,8536],{"class":3575,"line":3827},[3573,8527,8528],{"class":3590},"            t3 = tg.create_task(worker(",[3573,8530,8531],{"class":3638},"\"C\"",[3573,8533,4890],{"class":3590},[3573,8535,6797],{"class":4049},[3573,8537,5333],{"class":3590},[3573,8539,8540],{"class":3575,"line":3833},[3573,8541,3598],{"emptyLinePlaceholder":3597},[3573,8543,8544],{"class":3575,"line":3839},[3573,8545,8546],{"class":3579},"        # Вихід із блоку async with можливий ТІЛЬКИ після завершення всіх задач групи\n",[3573,8548,8549,8551,8553,8555,8557,8559,8562,8564,8566,8568,8571,8573,8575,8577,8580,8582,8584],{"class":3575,"line":3845},[3573,8550,4113],{"class":3608},[3573,8552,3612],{"class":3590},[3573,8554,3650],{"class":3604},[3573,8556,4880],{"class":3638},[3573,8558,3656],{"class":3604},[3573,8560,8561],{"class":3590},"t1.result()",[3573,8563,3662],{"class":3604},[3573,8565,4890],{"class":3638},[3573,8567,3656],{"class":3604},[3573,8569,8570],{"class":3590},"t2.result()",[3573,8572,3662],{"class":3604},[3573,8574,4890],{"class":3638},[3573,8576,3656],{"class":3604},[3573,8578,8579],{"class":3590},"t3.result()",[3573,8581,3662],{"class":3604},[3573,8583,3665],{"class":3638},[3573,8585,3668],{"class":3590},[3573,8587,8588,8591,8594,8597,8600],{"class":3575,"line":3851},[3573,8589,8590],{"class":3586},"    except",[3573,8592,8593],{"class":3590},"* ",[3573,8595,8596],{"class":3622},"ValueError",[3573,8598,8599],{"class":3586}," as",[3573,8601,8602],{"class":3590}," eg:\n",[3573,8604,8605],{"class":3575,"line":3856},[3573,8606,8607],{"class":3579},"        # Перехоплення кількох потенційних ValueError за допомогою except*\n",[3573,8609,8610,8612,8614,8616,8619,8621,8624,8626,8628],{"class":3575,"line":3862},[3573,8611,4113],{"class":3608},[3573,8613,3612],{"class":3590},[3573,8615,3650],{"class":3604},[3573,8617,8618],{"class":3638},"\"Виявлено помилки у TaskGroup: ",[3573,8620,3656],{"class":3604},[3573,8622,8623],{"class":3590},"eg.exceptions",[3573,8625,3662],{"class":3604},[3573,8627,3665],{"class":3638},[3573,8629,3668],{"class":3590},[3573,8631,8632],{"class":3575,"line":3868},[3573,8633,3598],{"emptyLinePlaceholder":3597},[3573,8635,8636],{"class":3575,"line":3874},[3573,8637,4193],{"class":3590},[8639,8640,8641,8642,8644,8645,8647],"tip",{},"Використовуйте ",[3438,8643,5093],{}," замість ",[3438,8646,4694],{}," для групування задач у нових проектах на Python 3.11+. Це суттєво полегшує налагодження, запобігає витоку ресурсів та гарантує передбачувану поведінку додатку при збоях.",[3458,8649],{},[3389,8651,8653],{"id":8652},"частина-iv-синхронізація-в-asyncio","Частина IV: Синхронізація в asyncio",[3394,8655,7453,8656,8658,8659,8661,8662,8664],{},[3438,8657,3451],{}," виконує весь прикладний код в одному потоці, це не позбавляє розробника від небезпеки стану гонки (race condition). В асинхронному середовищі точки перемикання контексту (",[3438,8660,3488],{},") визначають місця, де одна корутина може призупинитись, а інша — вклинитись у виконання та змінити спільний стан додатку. Для запобігання асинхронним станам гонки ",[3438,8663,3451],{}," пропонує примітиви синхронізації, аналогічні багатопотоковим, але адаптовані під роботу з корутинами.",[3458,8666],{},[3461,8668,8670,8673],{"id":8669},"asynciolock-взаємне-виключення-mutex",[3438,8671,8672],{},"asyncio.Lock"," — взаємне виключення (Mutex)",[3394,8675,8676,8677,8679],{},"Об'єкт ",[3438,8678,8672],{}," гарантує, що певна секція коду (критична зона) буде виконуватися лише однією корутиною одночасно.",[4267,8681,8683],{"id":8682},"основні-методи","Основні методи",[3936,8685,8686,8692,8698],{},[3425,8687,8688,8691],{},[3438,8689,8690],{},"async acquire()"," — захоплює замок. Якщо замок уже захоплений іншою корутиною, поточна корутина блокується в цій точці до моменту звільнення замка.",[3425,8693,8694,8697],{},[3438,8695,8696],{},"release()"," — звільняє замок, прокидаючи корутини, які очікують на його захоплення.",[3425,8699,8700,8703,8704,8706],{},[3438,8701,8702],{},"locked()"," — повертає ",[3438,8705,5414],{},", якщо замок наразі захоплений.",[8639,8708,8709,8710,8712,8713,8716],{},"Завжди використовуйте ",[3438,8711,8672],{}," через менеджер контексту: ",[3438,8714,8715],{},"async with lock:",". Це гарантує автоматичне звільнення замка навіть у випадку виникнення винятку в критичній зоні.",[3564,8718,8720],{"className":3566,"code":8719,"language":3568,"meta":3569,"style":3569},"# async_lock_demo.py\nimport asyncio\n\n# Спільний ресурс — глобальний лічильник\ncounter = 0\nlock = asyncio.Lock()\n\nasync def increment(name: str, n: int) -> None:\n    global counter\n    for _ in range(n):\n        # Без lock: між читанням та записом counter через await asyncio.sleep(0)\n        # інша корутина може встигнути змінити counter, що призведе до втрати інкременту\n        async with lock:          # безпечне захоплення замка\n            current = counter\n            await asyncio.sleep(0)  # симулюємо перемикання контексту\n            counter = current + 1\n    print(f\"[{name}] завершено, counter={counter}\")\n\nasync def main():\n    global counter\n    counter = 0\n\n    # Запускаємо два конкурентних інкрементори\n    await asyncio.gather(\n        increment(\"A\", 1000),\n        increment(\"B\", 1000),\n    )\n    print(f\"Фінальний counter: {counter}\")  # Завжди рівно 2000 завдяки Lock\n\nasyncio.run(main())\n",[3438,8721,8722,8727,8733,8737,8742,8750,8755,8759,8790,8798,8810,8815,8820,8832,8837,8851,8858,8888,8892,8902,8908,8915,8919,8924,8930,8945,8957,8961,8985,8989],{"__ignoreMap":3569},[3573,8723,8724],{"class":3575,"line":3576},[3573,8725,8726],{"class":3579},"# async_lock_demo.py\n",[3573,8728,8729,8731],{"class":3575,"line":3583},[3573,8730,3587],{"class":3586},[3573,8732,3591],{"class":3590},[3573,8734,8735],{"class":3575,"line":3594},[3573,8736,3598],{"emptyLinePlaceholder":3597},[3573,8738,8739],{"class":3575,"line":3601},[3573,8740,8741],{"class":3579},"# Спільний ресурс — глобальний лічильник\n",[3573,8743,8744,8747],{"class":3575,"line":3635},[3573,8745,8746],{"class":3590},"counter = ",[3573,8748,8749],{"class":4049},"0\n",[3573,8751,8752],{"class":3575,"line":3642},[3573,8753,8754],{"class":3590},"lock = asyncio.Lock()\n",[3573,8756,8757],{"class":3575,"line":3671},[3573,8758,3598],{"emptyLinePlaceholder":3597},[3573,8760,8761,8763,8765,8768,8770,8772,8774,8776,8778,8780,8782,8784,8786,8788],{"class":3575,"line":3676},[3573,8762,4005],{"class":3604},[3573,8764,4008],{"class":3604},[3573,8766,8767],{"class":3608}," increment",[3573,8769,3612],{"class":3590},[3573,8771,5194],{"class":3615},[3573,8773,3619],{"class":3590},[3573,8775,4736],{"class":3622},[3573,8777,4890],{"class":3590},[3573,8779,5769],{"class":3615},[3573,8781,3619],{"class":3590},[3573,8783,5645],{"class":3622},[3573,8785,3626],{"class":3590},[3573,8787,3629],{"class":3604},[3573,8789,3632],{"class":3590},[3573,8791,8792,8795],{"class":3575,"line":3695},[3573,8793,8794],{"class":3604},"    global",[3573,8796,8797],{"class":3590}," counter\n",[3573,8799,8800,8802,8804,8806,8808],{"class":3575,"line":3701},[3573,8801,4091],{"class":3586},[3573,8803,5667],{"class":3590},[3573,8805,4097],{"class":3586},[3573,8807,4100],{"class":3608},[3573,8809,5788],{"class":3590},[3573,8811,8812],{"class":3575,"line":3721},[3573,8813,8814],{"class":3579},"        # Без lock: між читанням та записом counter через await asyncio.sleep(0)\n",[3573,8816,8817],{"class":3575,"line":3727},[3573,8818,8819],{"class":3579},"        # інша корутина може встигнути змінити counter, що призведе до втрати інкременту\n",[3573,8821,8822,8824,8826,8829],{"class":3575,"line":3816},[3573,8823,8483],{"class":3586},[3573,8825,8486],{"class":3586},[3573,8827,8828],{"class":3590}," lock:          ",[3573,8830,8831],{"class":3579},"# безпечне захоплення замка\n",[3573,8833,8834],{"class":3575,"line":3822},[3573,8835,8836],{"class":3590},"            current = counter\n",[3573,8838,8839,8842,8844,8846,8848],{"class":3575,"line":3827},[3573,8840,8841],{"class":3586},"            await",[3573,8843,4046],{"class":3590},[3573,8845,5655],{"class":4049},[3573,8847,4926],{"class":3590},[3573,8849,8850],{"class":3579},"# симулюємо перемикання контексту\n",[3573,8852,8853,8856],{"class":3575,"line":3833},[3573,8854,8855],{"class":3590},"            counter = current + ",[3573,8857,5660],{"class":4049},[3573,8859,8860,8862,8864,8866,8868,8870,8872,8874,8877,8879,8882,8884,8886],{"class":3575,"line":3839},[3573,8861,3645],{"class":3608},[3573,8863,3612],{"class":3590},[3573,8865,3650],{"class":3604},[3573,8867,6625],{"class":3638},[3573,8869,3656],{"class":3604},[3573,8871,5194],{"class":3590},[3573,8873,3662],{"class":3604},[3573,8875,8876],{"class":3638},"] завершено, counter=",[3573,8878,3656],{"class":3604},[3573,8880,8881],{"class":3590},"counter",[3573,8883,3662],{"class":3604},[3573,8885,3665],{"class":3638},[3573,8887,3668],{"class":3590},[3573,8889,8890],{"class":3575,"line":3845},[3573,8891,3598],{"emptyLinePlaceholder":3597},[3573,8893,8894,8896,8898,8900],{"class":3575,"line":3851},[3573,8895,4005],{"class":3604},[3573,8897,4008],{"class":3604},[3573,8899,4161],{"class":3608},[3573,8901,5363],{"class":3590},[3573,8903,8904,8906],{"class":3575,"line":3856},[3573,8905,8794],{"class":3604},[3573,8907,8797],{"class":3590},[3573,8909,8910,8913],{"class":3575,"line":3862},[3573,8911,8912],{"class":3590},"    counter = ",[3573,8914,8749],{"class":4049},[3573,8916,8917],{"class":3575,"line":3868},[3573,8918,3598],{"emptyLinePlaceholder":3597},[3573,8920,8921],{"class":3575,"line":3874},[3573,8922,8923],{"class":3579},"    # Запускаємо два конкурентних інкрементори\n",[3573,8925,8926,8928],{"class":3575,"line":3880},[3573,8927,4043],{"class":3586},[3573,8929,7127],{"class":3590},[3573,8931,8932,8935,8937,8939,8942],{"class":3575,"line":3886},[3573,8933,8934],{"class":3590},"        increment(",[3573,8936,8503],{"class":3638},[3573,8938,4890],{"class":3590},[3573,8940,8941],{"class":4049},"1000",[3573,8943,8944],{"class":3590},"),\n",[3573,8946,8947,8949,8951,8953,8955],{"class":3575,"line":3891},[3573,8948,8934],{"class":3590},[3573,8950,8517],{"class":3638},[3573,8952,4890],{"class":3590},[3573,8954,8941],{"class":4049},[3573,8956,8944],{"class":3590},[3573,8958,8959],{"class":3575,"line":3897},[3573,8960,7147],{"class":3590},[3573,8962,8963,8965,8967,8969,8972,8974,8976,8978,8980,8982],{"class":3575,"line":3902},[3573,8964,3645],{"class":3608},[3573,8966,3612],{"class":3590},[3573,8968,3650],{"class":3604},[3573,8970,8971],{"class":3638},"\"Фінальний counter: ",[3573,8973,3656],{"class":3604},[3573,8975,8881],{"class":3590},[3573,8977,3662],{"class":3604},[3573,8979,3665],{"class":3638},[3573,8981,4926],{"class":3590},[3573,8983,8984],{"class":3579},"# Завжди рівно 2000 завдяки Lock\n",[3573,8986,8987],{"class":3575,"line":3908},[3573,8988,3598],{"emptyLinePlaceholder":3597},[3573,8990,8991],{"class":3575,"line":3913},[3573,8992,4193],{"class":3590},[3458,8994],{},[3461,8996,8998,9001],{"id":8997},"asynciosemaphore-обмеження-кількості-конкурентних-операцій",[3438,8999,9000],{},"asyncio.Semaphore"," — обмеження кількості конкурентних операцій",[3394,9003,9004,9006,9007,9010,9011,9013,9014,3507],{},[3438,9005,9000],{}," керує внутрішнім лічильником дозволів. Кожен виклик ",[3438,9008,9009],{},"acquire()"," зменшує лічильник на одиницю. Якщо лічильник стає рівним нулю, виклики ",[3438,9012,9009],{}," блокуються, доки інші корутини не викличуть ",[3438,9015,8696],{},[4267,9017,9019],{"id":9018},"сигнатура-ініціалізації","Сигнатура ініціалізації",[3564,9021,9023],{"className":3566,"code":9022,"language":3568,"meta":3569,"style":3569},"asyncio.Semaphore(value=1)\n",[3438,9024,9025],{"__ignoreMap":3569},[3573,9026,9027,9030,9032,9034,9036],{"class":3575,"line":3576},[3573,9028,9029],{"class":3590},"asyncio.Semaphore(",[3573,9031,4408],{"class":3615},[3573,9033,6476],{"class":3590},[3573,9035,4050],{"class":4049},[3573,9037,3668],{"class":3590},[5889,9039,9040],{},[5892,9041,9042,9043,5136],{"name":4408,"type":5645,"default":4050},"Початкова кількість доступних дозволів (має бути ",[3438,9044,9045],{},">= 0",[3394,9047,9048],{},"Найтиповіший сценарій застосування семафора — обмеження кількості одночасних запитів до зовнішнього веб-сервісу (наприклад, rate limiting \u002F backpressure) для уникнення блокувань чи перевантаження.",[3564,9050,9052],{"className":3566,"code":9051,"language":3568,"meta":3569,"style":3569},"# async_semaphore_demo.py\nimport asyncio\nimport time\n\nMAX_CONCURRENT_REQUESTS = 3\nsemaphore = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)\nactive_count = 0\n\nasync def fetch_with_limit(url: str, session_id: int) -> tuple[str, int]:\n    global active_count\n    # Одночасно блок async with пройдуть лише 3 корутини\n    async with semaphore:\n        active_count += 1\n        print(f\"  → [{session_id}] Запит: {url[-20:]}  (активних: {active_count})\")\n        try:\n            await asyncio.sleep(0.5)  # симуляція мережевого запиту\n            return url, 200\n        finally:\n            active_count -= 1\n            print(f\"  ← [{session_id}] Готово  (активних: {active_count})\")\n\nasync def main():\n    urls = [f\"https:\u002F\u002Fapi.example.com\u002Fresource\u002F{i}\" for i in range(10)]\n\n    t0 = time.perf_counter()\n    results = await asyncio.gather(\n        *[fetch_with_limit(url, i) for i, url in enumerate(urls)]\n    )\n    elapsed = time.perf_counter() - t0\n\n    print(f\"\\nОброблено {len(results)} URL за {elapsed:.2f}s\")\n    print(f\"(Без обмеження: ~0.5s; з Semaphore(3): ~{0.5 * (len(urls) \u002F\u002F MAX_CONCURRENT_REQUESTS):.1f}s)\")\n\nasyncio.run(main())\n",[3438,9053,9054,9059,9065,9071,9075,9083,9088,9095,9099,9135,9142,9147,9156,9163,9211,9218,9230,9239,9246,9253,9283,9287,9297,9329,9333,9337,9345,9363,9367,9372,9376,9414,9444,9448],{"__ignoreMap":3569},[3573,9055,9056],{"class":3575,"line":3576},[3573,9057,9058],{"class":3579},"# async_semaphore_demo.py\n",[3573,9060,9061,9063],{"class":3575,"line":3583},[3573,9062,3587],{"class":3586},[3573,9064,3591],{"class":3590},[3573,9066,9067,9069],{"class":3575,"line":3594},[3573,9068,3587],{"class":3586},[3573,9070,4718],{"class":3590},[3573,9072,9073],{"class":3575,"line":3601},[3573,9074,3598],{"emptyLinePlaceholder":3597},[3573,9076,9077,9080],{"class":3575,"line":3635},[3573,9078,9079],{"class":3590},"MAX_CONCURRENT_REQUESTS = ",[3573,9081,9082],{"class":4049},"3\n",[3573,9084,9085],{"class":3575,"line":3642},[3573,9086,9087],{"class":3590},"semaphore = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)\n",[3573,9089,9090,9093],{"class":3575,"line":3671},[3573,9091,9092],{"class":3590},"active_count = ",[3573,9094,8749],{"class":4049},[3573,9096,9097],{"class":3575,"line":3676},[3573,9098,3598],{"emptyLinePlaceholder":3597},[3573,9100,9101,9103,9105,9108,9110,9112,9114,9116,9118,9121,9123,9125,9127,9129,9131,9133],{"class":3575,"line":3695},[3573,9102,4005],{"class":3604},[3573,9104,4008],{"class":3604},[3573,9106,9107],{"class":3608}," fetch_with_limit",[3573,9109,3612],{"class":3590},[3573,9111,5710],{"class":3615},[3573,9113,3619],{"class":3590},[3573,9115,4736],{"class":3622},[3573,9117,4890],{"class":3590},[3573,9119,9120],{"class":3615},"session_id",[3573,9122,3619],{"class":3590},[3573,9124,5645],{"class":3622},[3573,9126,7023],{"class":3590},[3573,9128,4736],{"class":3622},[3573,9130,4890],{"class":3590},[3573,9132,5645],{"class":3622},[3573,9134,7032],{"class":3590},[3573,9136,9137,9139],{"class":3575,"line":3701},[3573,9138,8794],{"class":3604},[3573,9140,9141],{"class":3590}," active_count\n",[3573,9143,9144],{"class":3575,"line":3721},[3573,9145,9146],{"class":3579},"    # Одночасно блок async with пройдуть лише 3 корутини\n",[3573,9148,9149,9151,9153],{"class":3575,"line":3727},[3573,9150,5836],{"class":3586},[3573,9152,8486],{"class":3586},[3573,9154,9155],{"class":3590}," semaphore:\n",[3573,9157,9158,9161],{"class":3575,"line":3816},[3573,9159,9160],{"class":3590},"        active_count += ",[3573,9162,5660],{"class":4049},[3573,9164,9165,9167,9169,9171,9174,9176,9178,9180,9183,9185,9188,9191,9194,9196,9199,9201,9204,9206,9209],{"class":3575,"line":3822},[3573,9166,4113],{"class":3608},[3573,9168,3612],{"class":3590},[3573,9170,3650],{"class":3604},[3573,9172,9173],{"class":3638},"\"  → [",[3573,9175,3656],{"class":3604},[3573,9177,9120],{"class":3590},[3573,9179,3662],{"class":3604},[3573,9181,9182],{"class":3638},"] Запит: ",[3573,9184,3656],{"class":3604},[3573,9186,9187],{"class":3590},"url[-",[3573,9189,9190],{"class":4049},"20",[3573,9192,9193],{"class":3590},":]",[3573,9195,3662],{"class":3604},[3573,9197,9198],{"class":3638},"  (активних: ",[3573,9200,3656],{"class":3604},[3573,9202,9203],{"class":3590},"active_count",[3573,9205,3662],{"class":3604},[3573,9207,9208],{"class":3638},")\"",[3573,9210,3668],{"class":3590},[3573,9212,9213,9216],{"class":3575,"line":3827},[3573,9214,9215],{"class":3586},"        try",[3573,9217,3632],{"class":3590},[3573,9219,9220,9222,9224,9226,9228],{"class":3575,"line":3833},[3573,9221,8841],{"class":3586},[3573,9223,4046],{"class":3590},[3573,9225,4795],{"class":4049},[3573,9227,4926],{"class":3590},[3573,9229,7045],{"class":3579},[3573,9231,9232,9235,9237],{"class":3575,"line":3839},[3573,9233,9234],{"class":3586},"            return",[3573,9236,7052],{"class":3590},[3573,9238,7055],{"class":4049},[3573,9240,9241,9244],{"class":3575,"line":3845},[3573,9242,9243],{"class":3586},"        finally",[3573,9245,3632],{"class":3590},[3573,9247,9248,9251],{"class":3575,"line":3851},[3573,9249,9250],{"class":3590},"            active_count -= ",[3573,9252,5660],{"class":4049},[3573,9254,9255,9257,9259,9261,9264,9266,9268,9270,9273,9275,9277,9279,9281],{"class":3575,"line":3856},[3573,9256,7381],{"class":3608},[3573,9258,3612],{"class":3590},[3573,9260,3650],{"class":3604},[3573,9262,9263],{"class":3638},"\"  ← [",[3573,9265,3656],{"class":3604},[3573,9267,9120],{"class":3590},[3573,9269,3662],{"class":3604},[3573,9271,9272],{"class":3638},"] Готово  (активних: ",[3573,9274,3656],{"class":3604},[3573,9276,9203],{"class":3590},[3573,9278,3662],{"class":3604},[3573,9280,9208],{"class":3638},[3573,9282,3668],{"class":3590},[3573,9284,9285],{"class":3575,"line":3862},[3573,9286,3598],{"emptyLinePlaceholder":3597},[3573,9288,9289,9291,9293,9295],{"class":3575,"line":3868},[3573,9290,4005],{"class":3604},[3573,9292,4008],{"class":3604},[3573,9294,4161],{"class":3608},[3573,9296,5363],{"class":3590},[3573,9298,9299,9302,9304,9307,9309,9311,9313,9315,9317,9319,9321,9323,9325,9327],{"class":3575,"line":3874},[3573,9300,9301],{"class":3590},"    urls = [",[3573,9303,3650],{"class":3604},[3573,9305,9306],{"class":3638},"\"https:\u002F\u002Fapi.example.com\u002Fresource\u002F",[3573,9308,3656],{"class":3604},[3573,9310,4125],{"class":3590},[3573,9312,3662],{"class":3604},[3573,9314,3665],{"class":3638},[3573,9316,5839],{"class":3586},[3573,9318,4094],{"class":3590},[3573,9320,4097],{"class":3586},[3573,9322,4100],{"class":3608},[3573,9324,3612],{"class":3590},[3573,9326,8217],{"class":4049},[3573,9328,8220],{"class":3590},[3573,9330,9331],{"class":3575,"line":3880},[3573,9332,3598],{"emptyLinePlaceholder":3597},[3573,9334,9335],{"class":3575,"line":3886},[3573,9336,4839],{"class":3590},[3573,9338,9339,9341,9343],{"class":3575,"line":3891},[3573,9340,7309],{"class":3590},[3573,9342,3488],{"class":3586},[3573,9344,7127],{"class":3590},[3573,9346,9347,9350,9352,9355,9357,9360],{"class":3575,"line":3897},[3573,9348,9349],{"class":3590},"        *[fetch_with_limit(url, i) ",[3573,9351,5580],{"class":3586},[3573,9353,9354],{"class":3590}," i, url ",[3573,9356,4097],{"class":3586},[3573,9358,9359],{"class":3608}," enumerate",[3573,9361,9362],{"class":3590},"(urls)]\n",[3573,9364,9365],{"class":3575,"line":3902},[3573,9366,7147],{"class":3590},[3573,9368,9369],{"class":3575,"line":3908},[3573,9370,9371],{"class":3590},"    elapsed = time.perf_counter() - t0\n",[3573,9373,9374],{"class":3575,"line":3913},[3573,9375,3598],{"emptyLinePlaceholder":3597},[3573,9377,9378,9380,9382,9384,9386,9388,9391,9393,9395,9398,9400,9403,9405,9408,9410,9412],{"class":3575,"line":3919},[3573,9379,3645],{"class":3608},[3573,9381,3612],{"class":3590},[3573,9383,3650],{"class":3604},[3573,9385,3665],{"class":3638},[3573,9387,3714],{"class":3713},[3573,9389,9390],{"class":3638},"Оброблено ",[3573,9392,3656],{"class":3604},[3573,9394,7816],{"class":3608},[3573,9396,9397],{"class":3590},"(results)",[3573,9399,3662],{"class":3604},[3573,9401,9402],{"class":3638}," URL за ",[3573,9404,3656],{"class":3604},[3573,9406,9407],{"class":3590},"elapsed",[3573,9409,6863],{"class":3604},[3573,9411,4923],{"class":3638},[3573,9413,3668],{"class":3590},[3573,9415,9416,9418,9420,9422,9425,9427,9429,9432,9434,9437,9440,9442],{"class":3575,"line":3925},[3573,9417,3645],{"class":3608},[3573,9419,3612],{"class":3590},[3573,9421,3650],{"class":3604},[3573,9423,9424],{"class":3638},"\"(Без обмеження: ~0.5s; з Semaphore(3): ~",[3573,9426,3656],{"class":3604},[3573,9428,4795],{"class":4049},[3573,9430,9431],{"class":3590}," * (",[3573,9433,7816],{"class":3608},[3573,9435,9436],{"class":3590},"(urls) \u002F\u002F MAX_CONCURRENT_REQUESTS)",[3573,9438,9439],{"class":3604},":.1f}",[3573,9441,6671],{"class":3638},[3573,9443,3668],{"class":3590},[3573,9445,9446],{"class":3575,"line":4576},[3573,9447,3598],{"emptyLinePlaceholder":3597},[3573,9449,9450],{"class":3575,"line":4582},[3573,9451,4193],{"class":3590},[3458,9453],{},[3461,9455,9457,9460],{"id":9456},"asyncioevent-асинхронна-сигналізація-між-корутинами",[3438,9458,9459],{},"asyncio.Event"," — асинхронна сигналізація між корутинами",[3394,9462,8676,9463,9465,9466,5136],{},[3438,9464,9459],{}," є найпростішим способом координації кількох корутин за принципом «один сигналізує — багато чекають». Він зберігає внутрішній булевий прапорець (початково ",[3438,9467,6952],{},[4267,9469,8683],{"id":9470},"основні-методи-1",[3936,9472,9473,9481,9490,9498],{},[3425,9474,9475,8703,9478,9480],{},[3438,9476,9477],{},"is_set()",[3438,9479,5414],{},", якщо прапорець встановлений.",[3425,9482,9483,9486,9487,9489],{},[3438,9484,9485],{},"set()"," — встановлює прапорець у ",[3438,9488,5414],{}," та миттєво розблоковує всі корутини, які чекають на цю подію.",[3425,9491,9492,9495,9496,3507],{},[3438,9493,9494],{},"clear()"," — скидає прапорець у ",[3438,9497,6952],{},[3425,9499,9500,9503,9504,9506],{},[3438,9501,9502],{},"async wait()"," — блокує поточну корутину, доки прапорець події не стане ",[3438,9505,5414],{},". Якщо прапорець вже встановлений, виклик повертає керування негайно.",[3564,9508,9510],{"className":3566,"code":9509,"language":3568,"meta":3569,"style":3569},"# async_event_demo.py\nimport asyncio\n\nasync def producer(event: asyncio.Event, data: list) -> None:\n    \"\"\"Підготовує спільні дані і сигналізує про готовність.\"\"\"\n    print(\"[Producer] Готую дані...\")\n    await asyncio.sleep(1.0)\n    data.extend([1, 2, 3, 4, 5])\n    print(\"[Producer] Дані готові!\")\n    event.set()   # Встановлюємо подію, щоб зняти блок з чекаючих корутин\n\nasync def consumer(event: asyncio.Event, data: list, consumer_id: int) -> None:\n    \"\"\"Очікує готовності даних та обробляє їх.\"\"\"\n    print(f\"[Consumer-{consumer_id}] Чекаю даних...\")\n    await event.wait()   # Очікування сигналу від Producer\n    print(f\"[Consumer-{consumer_id}] Отримав {len(data)} елементів: {data}\")\n\nasync def main():\n    ready_event = asyncio.Event()\n    shared_data: list[int] = []\n\n    # Запускаємо конкурентно одного постачальника та трьох споживачів\n    await asyncio.gather(\n        producer(ready_event, shared_data),\n        consumer(ready_event, shared_data, 1),\n        consumer(ready_event, shared_data, 2),\n        consumer(ready_event, shared_data, 3),\n    )\n\nasyncio.run(main())\n",[3438,9511,9512,9517,9523,9527,9557,9562,9573,9583,9611,9622,9630,9634,9670,9675,9697,9707,9748,9752,9762,9767,9777,9781,9786,9792,9797,9806,9814,9822,9826,9830],{"__ignoreMap":3569},[3573,9513,9514],{"class":3575,"line":3576},[3573,9515,9516],{"class":3579},"# async_event_demo.py\n",[3573,9518,9519,9521],{"class":3575,"line":3583},[3573,9520,3587],{"class":3586},[3573,9522,3591],{"class":3590},[3573,9524,9525],{"class":3575,"line":3594},[3573,9526,3598],{"emptyLinePlaceholder":3597},[3573,9528,9529,9531,9533,9536,9538,9541,9544,9546,9548,9551,9553,9555],{"class":3575,"line":3601},[3573,9530,4005],{"class":3604},[3573,9532,4008],{"class":3604},[3573,9534,9535],{"class":3608}," producer",[3573,9537,3612],{"class":3590},[3573,9539,9540],{"class":3615},"event",[3573,9542,9543],{"class":3590},": asyncio.Event, ",[3573,9545,3616],{"class":3615},[3573,9547,3619],{"class":3590},[3573,9549,9550],{"class":3622},"list",[3573,9552,3626],{"class":3590},[3573,9554,3629],{"class":3604},[3573,9556,3632],{"class":3590},[3573,9558,9559],{"class":3575,"line":3635},[3573,9560,9561],{"class":3638},"    \"\"\"Підготовує спільні дані і сигналізує про готовність.\"\"\"\n",[3573,9563,9564,9566,9568,9571],{"class":3575,"line":3642},[3573,9565,3645],{"class":3608},[3573,9567,3612],{"class":3590},[3573,9569,9570],{"class":3638},"\"[Producer] Готую дані...\"",[3573,9572,3668],{"class":3590},[3573,9574,9575,9577,9579,9581],{"class":3575,"line":3671},[3573,9576,4043],{"class":3586},[3573,9578,4046],{"class":3590},[3573,9580,6748],{"class":4049},[3573,9582,3668],{"class":3590},[3573,9584,9585,9588,9590,9592,9595,9597,9599,9601,9604,9606,9608],{"class":3575,"line":3676},[3573,9586,9587],{"class":3590},"    data.extend([",[3573,9589,4050],{"class":4049},[3573,9591,4890],{"class":3590},[3573,9593,9594],{"class":4049},"2",[3573,9596,4890],{"class":3590},[3573,9598,4105],{"class":4049},[3573,9600,4890],{"class":3590},[3573,9602,9603],{"class":4049},"4",[3573,9605,4890],{"class":3590},[3573,9607,5850],{"class":4049},[3573,9609,9610],{"class":3590},"])\n",[3573,9612,9613,9615,9617,9620],{"class":3575,"line":3695},[3573,9614,3645],{"class":3608},[3573,9616,3612],{"class":3590},[3573,9618,9619],{"class":3638},"\"[Producer] Дані готові!\"",[3573,9621,3668],{"class":3590},[3573,9623,9624,9627],{"class":3575,"line":3701},[3573,9625,9626],{"class":3590},"    event.set()   ",[3573,9628,9629],{"class":3579},"# Встановлюємо подію, щоб зняти блок з чекаючих корутин\n",[3573,9631,9632],{"class":3575,"line":3721},[3573,9633,3598],{"emptyLinePlaceholder":3597},[3573,9635,9636,9638,9640,9643,9645,9647,9649,9651,9653,9655,9657,9660,9662,9664,9666,9668],{"class":3575,"line":3727},[3573,9637,4005],{"class":3604},[3573,9639,4008],{"class":3604},[3573,9641,9642],{"class":3608}," consumer",[3573,9644,3612],{"class":3590},[3573,9646,9540],{"class":3615},[3573,9648,9543],{"class":3590},[3573,9650,3616],{"class":3615},[3573,9652,3619],{"class":3590},[3573,9654,9550],{"class":3622},[3573,9656,4890],{"class":3590},[3573,9658,9659],{"class":3615},"consumer_id",[3573,9661,3619],{"class":3590},[3573,9663,5645],{"class":3622},[3573,9665,3626],{"class":3590},[3573,9667,3629],{"class":3604},[3573,9669,3632],{"class":3590},[3573,9671,9672],{"class":3575,"line":3816},[3573,9673,9674],{"class":3638},"    \"\"\"Очікує готовності даних та обробляє їх.\"\"\"\n",[3573,9676,9677,9679,9681,9683,9686,9688,9690,9692,9695],{"class":3575,"line":3822},[3573,9678,3645],{"class":3608},[3573,9680,3612],{"class":3590},[3573,9682,3650],{"class":3604},[3573,9684,9685],{"class":3638},"\"[Consumer-",[3573,9687,3656],{"class":3604},[3573,9689,9659],{"class":3590},[3573,9691,3662],{"class":3604},[3573,9693,9694],{"class":3638},"] Чекаю даних...\"",[3573,9696,3668],{"class":3590},[3573,9698,9699,9701,9704],{"class":3575,"line":3827},[3573,9700,4043],{"class":3586},[3573,9702,9703],{"class":3590}," event.wait()   ",[3573,9705,9706],{"class":3579},"# Очікування сигналу від Producer\n",[3573,9708,9709,9711,9713,9715,9717,9719,9721,9723,9726,9728,9730,9733,9735,9738,9740,9742,9744,9746],{"class":3575,"line":3833},[3573,9710,3645],{"class":3608},[3573,9712,3612],{"class":3590},[3573,9714,3650],{"class":3604},[3573,9716,9685],{"class":3638},[3573,9718,3656],{"class":3604},[3573,9720,9659],{"class":3590},[3573,9722,3662],{"class":3604},[3573,9724,9725],{"class":3638},"] Отримав ",[3573,9727,3656],{"class":3604},[3573,9729,7816],{"class":3608},[3573,9731,9732],{"class":3590},"(data)",[3573,9734,3662],{"class":3604},[3573,9736,9737],{"class":3638}," елементів: ",[3573,9739,3656],{"class":3604},[3573,9741,3616],{"class":3590},[3573,9743,3662],{"class":3604},[3573,9745,3665],{"class":3638},[3573,9747,3668],{"class":3590},[3573,9749,9750],{"class":3575,"line":3839},[3573,9751,3598],{"emptyLinePlaceholder":3597},[3573,9753,9754,9756,9758,9760],{"class":3575,"line":3845},[3573,9755,4005],{"class":3604},[3573,9757,4008],{"class":3604},[3573,9759,4161],{"class":3608},[3573,9761,5363],{"class":3590},[3573,9763,9764],{"class":3575,"line":3851},[3573,9765,9766],{"class":3590},"    ready_event = asyncio.Event()\n",[3573,9768,9769,9772,9774],{"class":3575,"line":3856},[3573,9770,9771],{"class":3590},"    shared_data: list[",[3573,9773,5645],{"class":3622},[3573,9775,9776],{"class":3590},"] = []\n",[3573,9778,9779],{"class":3575,"line":3862},[3573,9780,3598],{"emptyLinePlaceholder":3597},[3573,9782,9783],{"class":3575,"line":3868},[3573,9784,9785],{"class":3579},"    # Запускаємо конкурентно одного постачальника та трьох споживачів\n",[3573,9787,9788,9790],{"class":3575,"line":3874},[3573,9789,4043],{"class":3586},[3573,9791,7127],{"class":3590},[3573,9793,9794],{"class":3575,"line":3880},[3573,9795,9796],{"class":3590},"        producer(ready_event, shared_data),\n",[3573,9798,9799,9802,9804],{"class":3575,"line":3886},[3573,9800,9801],{"class":3590},"        consumer(ready_event, shared_data, ",[3573,9803,4050],{"class":4049},[3573,9805,8944],{"class":3590},[3573,9807,9808,9810,9812],{"class":3575,"line":3891},[3573,9809,9801],{"class":3590},[3573,9811,9594],{"class":4049},[3573,9813,8944],{"class":3590},[3573,9815,9816,9818,9820],{"class":3575,"line":3897},[3573,9817,9801],{"class":3590},[3573,9819,4105],{"class":4049},[3573,9821,8944],{"class":3590},[3573,9823,9824],{"class":3575,"line":3902},[3573,9825,7147],{"class":3590},[3573,9827,9828],{"class":3575,"line":3908},[3573,9829,3598],{"emptyLinePlaceholder":3597},[3573,9831,9832],{"class":3575,"line":3913},[3573,9833,4193],{"class":3590},[3458,9835],{},[3461,9837,9839,9842],{"id":9838},"asyncioqueue-асинхронна-черга-для-патерну-producer-consumer",[3438,9840,9841],{},"asyncio.Queue"," — асинхронна черга для патерну Producer-Consumer",[3394,9844,9845,9846,9848,9849,9852],{},"Черга ",[3438,9847,9841],{}," забезпечує безпечний обмін повідомленнями між різними корутинами без використання замків та прапорців. Вона повністю аналогічна стандартній синхронній ",[3438,9850,9851],{},"queue.Queue",", але її основні методи є корутинами і не блокують системні потоки ОС при заповненні чи спустошенні черги.",[4267,9854,9019],{"id":9855},"сигнатура-ініціалізації-1",[3564,9857,9859],{"className":3566,"code":9858,"language":3568,"meta":3569,"style":3569},"asyncio.Queue(maxsize=0)\n",[3438,9860,9861],{"__ignoreMap":3569},[3573,9862,9863,9866,9869,9871,9873],{"class":3575,"line":3576},[3573,9864,9865],{"class":3590},"asyncio.Queue(",[3573,9867,9868],{"class":3615},"maxsize",[3573,9870,6476],{"class":3590},[3573,9872,5655],{"class":4049},[3573,9874,3668],{"class":3590},[5889,9876,9877],{},[5892,9878,9879,9880,9883,9884,9887],{"name":9868,"type":5645,"default":5655},"Максимальний розмір черги. Якщо ліміт перевищено, метод ",[3438,9881,9882],{},"put()"," блокується, доки в черзі не з'явиться вільне місце (реалізація backpressure). Якщо ",[3438,9885,9886],{},"maxsize \u003C= 0",", черга має необмежений розмір.",[4267,9889,9891],{"id":9890},"ключові-методи","Ключові методи",[3936,9893,9894,9900,9906,9921,9927],{},[3425,9895,9896,9899],{},[3438,9897,9898],{},"async put(item)"," — кладе елемент у чергу. Якщо черга повна, очікує звільнення місця.",[3425,9901,9902,9905],{},[3438,9903,9904],{},"async get()"," — вилучає та повертає елемент із черги. Якщо черга порожня, очікує надходження нових елементів.",[3425,9907,9908,4369,9911,9914,9915,4357,9918,3507],{},[3438,9909,9910],{},"put_nowait(item)",[3438,9912,9913],{},"get_nowait()"," — неблокуючі варіанти методів. Якщо черга повна\u002Fпорожня, вони миттєво генерують виняток ",[3438,9916,9917],{},"QueueFull",[3438,9919,9920],{},"QueueEmpty",[3425,9922,9923,9926],{},[3438,9924,9925],{},"task_done()"," — сигналізує, що раніше вилучена задача успішно оброблена. Викликається споживачем після завершення роботи над елементом.",[3425,9928,9929,9932,9933,9935,9936,5136],{},[3438,9930,9931],{},"async join()"," — блокується, доки всі завдання в черзі не будуть повністю оброблені (кількість викликів ",[3438,9934,9925],{}," зрівняється з кількістю ",[3438,9937,9882],{},[3564,9939,9941],{"className":3566,"code":9940,"language":3568,"meta":3569,"style":3569},"# async_queue_demo.py\nimport asyncio\nimport random\n\nasync def producer(queue: asyncio.Queue, n_items: int) -> None:\n    \"\"\"Генерує завдання та додає їх у чергу.\"\"\"\n    for i in range(n_items):\n        item = random.randint(1, 100)\n        await queue.put(item)          # Блокується, якщо черга заповнена\n        print(f\"  [Producer] → {item} (у черзі: {queue.qsize()})\")\n        await asyncio.sleep(0.1)\n\n    # Додаємо маркер завершення (sentinel) для кожного споживача\n    await queue.put(None)\n    await queue.put(None)\n    print(\"  [Producer] Всі завдання успішно надіслані\")\n\nasync def consumer(queue: asyncio.Queue, name: str) -> None:\n    \"\"\"Вилучає завдання з черги та обробляє їх.\"\"\"\n    total = 0\n    while True:\n        item = await queue.get()       # Блокується, якщо черга порожня\n        if item is None:\n            print(f\"  [{name}] Отримано маркер завершення. Фінальна сума={total}\")\n            queue.task_done()\n            break\n        total += item\n        print(f\"  [{name}] Обробляю {item}\")\n        await asyncio.sleep(0.2)       # Споживач працює повільніше за постачальника\n        queue.task_done()\n\nasync def main():\n    # Обмежуємо розмір черги до 5 елементів для стримування продюсера\n    queue: asyncio.Queue[int | None] = asyncio.Queue(maxsize=5)\n\n    await asyncio.gather(\n        producer(queue, 8),\n        consumer(queue, \"Consumer-1\"),\n        consumer(queue, \"Consumer-2\"),\n    )\n\nasyncio.run(main())\n",[3438,9942,9943,9948,9954,9960,9964,9993,9998,10011,10025,10035,10067,10077,10081,10086,10097,10107,10118,10122,10148,10153,10160,10170,10183,10198,10229,10234,10239,10244,10273,10288,10293,10297,10307,10312,10335,10339,10345,10355,10365,10374,10378,10382],{"__ignoreMap":3569},[3573,9944,9945],{"class":3575,"line":3576},[3573,9946,9947],{"class":3579},"# async_queue_demo.py\n",[3573,9949,9950,9952],{"class":3575,"line":3583},[3573,9951,3587],{"class":3586},[3573,9953,3591],{"class":3590},[3573,9955,9956,9958],{"class":3575,"line":3594},[3573,9957,3587],{"class":3586},[3573,9959,8127],{"class":3590},[3573,9961,9962],{"class":3575,"line":3601},[3573,9963,3598],{"emptyLinePlaceholder":3597},[3573,9965,9966,9968,9970,9972,9974,9977,9980,9983,9985,9987,9989,9991],{"class":3575,"line":3635},[3573,9967,4005],{"class":3604},[3573,9969,4008],{"class":3604},[3573,9971,9535],{"class":3608},[3573,9973,3612],{"class":3590},[3573,9975,9976],{"class":3615},"queue",[3573,9978,9979],{"class":3590},": asyncio.Queue, ",[3573,9981,9982],{"class":3615},"n_items",[3573,9984,3619],{"class":3590},[3573,9986,5645],{"class":3622},[3573,9988,3626],{"class":3590},[3573,9990,3629],{"class":3604},[3573,9992,3632],{"class":3590},[3573,9994,9995],{"class":3575,"line":3642},[3573,9996,9997],{"class":3638},"    \"\"\"Генерує завдання та додає їх у чергу.\"\"\"\n",[3573,9999,10000,10002,10004,10006,10008],{"class":3575,"line":3671},[3573,10001,4091],{"class":3586},[3573,10003,4094],{"class":3590},[3573,10005,4097],{"class":3586},[3573,10007,4100],{"class":3608},[3573,10009,10010],{"class":3590},"(n_items):\n",[3573,10012,10013,10016,10018,10020,10023],{"class":3575,"line":3676},[3573,10014,10015],{"class":3590},"        item = random.randint(",[3573,10017,4050],{"class":4049},[3573,10019,4890],{"class":3590},[3573,10021,10022],{"class":4049},"100",[3573,10024,3668],{"class":3590},[3573,10026,10027,10029,10032],{"class":3575,"line":3695},[3573,10028,4141],{"class":3586},[3573,10030,10031],{"class":3590}," queue.put(item)          ",[3573,10033,10034],{"class":3579},"# Блокується, якщо черга заповнена\n",[3573,10036,10037,10039,10041,10043,10046,10048,10051,10053,10056,10058,10061,10063,10065],{"class":3575,"line":3701},[3573,10038,4113],{"class":3608},[3573,10040,3612],{"class":3590},[3573,10042,3650],{"class":3604},[3573,10044,10045],{"class":3638},"\"  [Producer] → ",[3573,10047,3656],{"class":3604},[3573,10049,10050],{"class":3590},"item",[3573,10052,3662],{"class":3604},[3573,10054,10055],{"class":3638}," (у черзі: ",[3573,10057,3656],{"class":3604},[3573,10059,10060],{"class":3590},"queue.qsize()",[3573,10062,3662],{"class":3604},[3573,10064,9208],{"class":3638},[3573,10066,3668],{"class":3590},[3573,10068,10069,10071,10073,10075],{"class":3575,"line":3721},[3573,10070,4141],{"class":3586},[3573,10072,4046],{"class":3590},[3573,10074,5213],{"class":4049},[3573,10076,3668],{"class":3590},[3573,10078,10079],{"class":3575,"line":3727},[3573,10080,3598],{"emptyLinePlaceholder":3597},[3573,10082,10083],{"class":3575,"line":3816},[3573,10084,10085],{"class":3579},"    # Додаємо маркер завершення (sentinel) для кожного споживача\n",[3573,10087,10088,10090,10093,10095],{"class":3575,"line":3822},[3573,10089,4043],{"class":3586},[3573,10091,10092],{"class":3590}," queue.put(",[3573,10094,3629],{"class":3604},[3573,10096,3668],{"class":3590},[3573,10098,10099,10101,10103,10105],{"class":3575,"line":3827},[3573,10100,4043],{"class":3586},[3573,10102,10092],{"class":3590},[3573,10104,3629],{"class":3604},[3573,10106,3668],{"class":3590},[3573,10108,10109,10111,10113,10116],{"class":3575,"line":3833},[3573,10110,3645],{"class":3608},[3573,10112,3612],{"class":3590},[3573,10114,10115],{"class":3638},"\"  [Producer] Всі завдання успішно надіслані\"",[3573,10117,3668],{"class":3590},[3573,10119,10120],{"class":3575,"line":3839},[3573,10121,3598],{"emptyLinePlaceholder":3597},[3573,10123,10124,10126,10128,10130,10132,10134,10136,10138,10140,10142,10144,10146],{"class":3575,"line":3845},[3573,10125,4005],{"class":3604},[3573,10127,4008],{"class":3604},[3573,10129,9642],{"class":3608},[3573,10131,3612],{"class":3590},[3573,10133,9976],{"class":3615},[3573,10135,9979],{"class":3590},[3573,10137,5194],{"class":3615},[3573,10139,3619],{"class":3590},[3573,10141,4736],{"class":3622},[3573,10143,3626],{"class":3590},[3573,10145,3629],{"class":3604},[3573,10147,3632],{"class":3590},[3573,10149,10150],{"class":3575,"line":3851},[3573,10151,10152],{"class":3638},"    \"\"\"Вилучає завдання з черги та обробляє їх.\"\"\"\n",[3573,10154,10155,10158],{"class":3575,"line":3856},[3573,10156,10157],{"class":3590},"    total = ",[3573,10159,8749],{"class":4049},[3573,10161,10162,10165,10168],{"class":3575,"line":3862},[3573,10163,10164],{"class":3586},"    while",[3573,10166,10167],{"class":3604}," True",[3573,10169,3632],{"class":3590},[3573,10171,10172,10175,10177,10180],{"class":3575,"line":3868},[3573,10173,10174],{"class":3590},"        item = ",[3573,10176,3488],{"class":3586},[3573,10178,10179],{"class":3590}," queue.get()       ",[3573,10181,10182],{"class":3579},"# Блокується, якщо черга порожня\n",[3573,10184,10185,10187,10190,10193,10196],{"class":3575,"line":3874},[3573,10186,7216],{"class":3586},[3573,10188,10189],{"class":3590}," item ",[3573,10191,10192],{"class":3604},"is",[3573,10194,10195],{"class":3604}," None",[3573,10197,3632],{"class":3590},[3573,10199,10200,10202,10204,10206,10209,10211,10213,10215,10218,10220,10223,10225,10227],{"class":3575,"line":3880},[3573,10201,7381],{"class":3608},[3573,10203,3612],{"class":3590},[3573,10205,3650],{"class":3604},[3573,10207,10208],{"class":3638},"\"  [",[3573,10210,3656],{"class":3604},[3573,10212,5194],{"class":3590},[3573,10214,3662],{"class":3604},[3573,10216,10217],{"class":3638},"] Отримано маркер завершення. Фінальна сума=",[3573,10219,3656],{"class":3604},[3573,10221,10222],{"class":3590},"total",[3573,10224,3662],{"class":3604},[3573,10226,3665],{"class":3638},[3573,10228,3668],{"class":3590},[3573,10230,10231],{"class":3575,"line":3886},[3573,10232,10233],{"class":3590},"            queue.task_done()\n",[3573,10235,10236],{"class":3575,"line":3891},[3573,10237,10238],{"class":3586},"            break\n",[3573,10240,10241],{"class":3575,"line":3897},[3573,10242,10243],{"class":3590},"        total += item\n",[3573,10245,10246,10248,10250,10252,10254,10256,10258,10260,10263,10265,10267,10269,10271],{"class":3575,"line":3902},[3573,10247,4113],{"class":3608},[3573,10249,3612],{"class":3590},[3573,10251,3650],{"class":3604},[3573,10253,10208],{"class":3638},[3573,10255,3656],{"class":3604},[3573,10257,5194],{"class":3590},[3573,10259,3662],{"class":3604},[3573,10261,10262],{"class":3638},"] Обробляю ",[3573,10264,3656],{"class":3604},[3573,10266,10050],{"class":3590},[3573,10268,3662],{"class":3604},[3573,10270,3665],{"class":3638},[3573,10272,3668],{"class":3590},[3573,10274,10275,10277,10279,10282,10285],{"class":3575,"line":3908},[3573,10276,4141],{"class":3586},[3573,10278,4046],{"class":3590},[3573,10280,10281],{"class":4049},"0.2",[3573,10283,10284],{"class":3590},")       ",[3573,10286,10287],{"class":3579},"# Споживач працює повільніше за постачальника\n",[3573,10289,10290],{"class":3575,"line":3913},[3573,10291,10292],{"class":3590},"        queue.task_done()\n",[3573,10294,10295],{"class":3575,"line":3919},[3573,10296,3598],{"emptyLinePlaceholder":3597},[3573,10298,10299,10301,10303,10305],{"class":3575,"line":3925},[3573,10300,4005],{"class":3604},[3573,10302,4008],{"class":3604},[3573,10304,4161],{"class":3608},[3573,10306,5363],{"class":3590},[3573,10308,10309],{"class":3575,"line":4576},[3573,10310,10311],{"class":3579},"    # Обмежуємо розмір черги до 5 елементів для стримування продюсера\n",[3573,10313,10314,10317,10319,10322,10324,10327,10329,10331,10333],{"class":3575,"line":4582},[3573,10315,10316],{"class":3590},"    queue: asyncio.Queue[",[3573,10318,5645],{"class":3622},[3573,10320,10321],{"class":3590}," | ",[3573,10323,3629],{"class":3604},[3573,10325,10326],{"class":3590},"] = asyncio.Queue(",[3573,10328,9868],{"class":3615},[3573,10330,6476],{"class":3590},[3573,10332,5850],{"class":4049},[3573,10334,3668],{"class":3590},[3573,10336,10337],{"class":3575,"line":4588},[3573,10338,3598],{"emptyLinePlaceholder":3597},[3573,10340,10341,10343],{"class":3575,"line":4593},[3573,10342,4043],{"class":3586},[3573,10344,7127],{"class":3590},[3573,10346,10347,10350,10353],{"class":3575,"line":4599},[3573,10348,10349],{"class":3590},"        producer(queue, ",[3573,10351,10352],{"class":4049},"8",[3573,10354,8944],{"class":3590},[3573,10356,10357,10360,10363],{"class":3575,"line":4604},[3573,10358,10359],{"class":3590},"        consumer(queue, ",[3573,10361,10362],{"class":3638},"\"Consumer-1\"",[3573,10364,8944],{"class":3590},[3573,10366,10367,10369,10372],{"class":3575,"line":4609},[3573,10368,10359],{"class":3590},[3573,10370,10371],{"class":3638},"\"Consumer-2\"",[3573,10373,8944],{"class":3590},[3573,10375,10376],{"class":3575,"line":4614},[3573,10377,7147],{"class":3590},[3573,10379,10380],{"class":3575,"line":4620},[3573,10381,3598],{"emptyLinePlaceholder":3597},[3573,10383,10384],{"class":3575,"line":4626},[3573,10385,4193],{"class":3590},[3458,10387],{},[3461,10389,10391,10392,3554,10395],{"id":10390},"таймаути-asynciotimeout-та-asynciowait_for","Таймаути: ",[3438,10393,10394],{},"asyncio.timeout()",[3438,10396,10397],{},"asyncio.wait_for()",[3394,10399,10400,10401,10403],{},"Для контролю часу виконання мережевих запитів або довгих операцій в ",[3438,10402,3451],{}," використовуються механізми обмеження часу (timeout).",[4267,10405,10407,10408,10410],{"id":10406},"_1-asynciowait_for-класичний-підхід","1. ",[3438,10409,10397],{}," (класичний підхід)",[3394,10412,10413,10414,10417,10418,3507],{},"Обгортає одну корутину та обмежує час її очікування. Якщо ліміт вичерпано, задача скасовується (",[3438,10415,10416],{},"task.cancel()",") та генерується виняток ",[3438,10419,10420],{},"asyncio.TimeoutError",[4267,10422,10424,10425,10427],{"id":10423},"_2-asynciotimeout-сучасний-підхід-з-python-311","2. ",[3438,10426,10394],{}," (сучасний підхід з Python 3.11+)",[3394,10429,10430,10431,10433],{},"Асинхронний контекстний менеджер, який дозволяє обмежувати час виконання цілого блоку коду, що може містити кілька різних ",[3438,10432,3488],{}," інструкцій.",[4267,10435,10437,10438,10441],{"id":10436},"_3-asynciotimeout_at-python-311","3. ",[3438,10439,10440],{},"asyncio.timeout_at()"," (Python 3.11+)",[3394,10443,10444,10445,10448,10449,10452],{},"Аналогічний до ",[3438,10446,10447],{},"timeout()",", але приймає не відносний час очікування, а абсолютний час Event Loop (можна отримати за допомогою ",[3438,10450,10451],{},"loop.time()","), після досягнення якого блок коду буде перервано.",[3564,10454,10456],{"className":3566,"code":10455,"language":3568,"meta":3569,"style":3569},"# async_timeout_demo.py\nimport asyncio\n\nasync def slow_operation() -> str:\n    \"\"\"Симулює тривале виконання операції.\"\"\"\n    await asyncio.sleep(5.0)\n    return \"повільний результат\"\n\nasync def main():\n    # 1. Сучасний підхід: asyncio.timeout() (Python 3.11+)\n    try:\n        async with asyncio.timeout(1.0):  # таймаут на блок коду\n            result = await slow_operation()\n    except asyncio.TimeoutError:\n        print(\"asyncio.timeout: операція перевищила ліміт в 1s і була скасована\")\n\n    # 2. Класичний підхід: asyncio.wait_for()\n    try:\n        result = await asyncio.wait_for(slow_operation(), timeout=1.0)\n    except asyncio.TimeoutError:\n        print(\"wait_for: операція перевищила ліміт в 1s\")\n\n    # 3. Динамічне коригування дедлайну\n    async def fetch_with_retry(url: str, attempts: int = 3) -> str:\n        for attempt in range(1, attempts + 1):\n            try:\n                # З кожною наступною спробою збільшуємо таймаут\n                async with asyncio.timeout(2.0 * attempt) as to:\n                    # Можливість змінити таймаут динамічно в процесі:\n                    # to.reschedule(loop.time() + new_delay)\n                    await asyncio.sleep(1.5)  # симуляція запиту\n                    return f\"OK from {url} (спроба {attempt})\"\n            except asyncio.TimeoutError:\n                print(f\"  Спроба {attempt} перевищила таймаут\")\n        raise RuntimeError(f\"Всі {attempts} спроб завершились невдачею\")\n\n    result = await fetch_with_retry(\"https:\u002F\u002Fapi.example.com\")\n    print(f\"Результат: {result}\")\n\nasyncio.run(main())\n",[3438,10457,10458,10463,10469,10473,10488,10493,10503,10510,10514,10524,10529,10535,10552,10562,10569,10580,10584,10589,10595,10613,10619,10630,10634,10639,10676,10698,10705,10710,10729,10734,10739,10753,10782,10789,10812,10838,10842,10856,10877,10881],{"__ignoreMap":3569},[3573,10459,10460],{"class":3575,"line":3576},[3573,10461,10462],{"class":3579},"# async_timeout_demo.py\n",[3573,10464,10465,10467],{"class":3575,"line":3583},[3573,10466,3587],{"class":3586},[3573,10468,3591],{"class":3590},[3573,10470,10471],{"class":3575,"line":3594},[3573,10472,3598],{"emptyLinePlaceholder":3597},[3573,10474,10475,10477,10479,10482,10484,10486],{"class":3575,"line":3601},[3573,10476,4005],{"class":3604},[3573,10478,4008],{"class":3604},[3573,10480,10481],{"class":3608}," slow_operation",[3573,10483,4014],{"class":3590},[3573,10485,4736],{"class":3622},[3573,10487,3632],{"class":3590},[3573,10489,10490],{"class":3575,"line":3635},[3573,10491,10492],{"class":3638},"    \"\"\"Симулює тривале виконання операції.\"\"\"\n",[3573,10494,10495,10497,10499,10501],{"class":3575,"line":3642},[3573,10496,4043],{"class":3586},[3573,10498,4046],{"class":3590},[3573,10500,7965],{"class":4049},[3573,10502,3668],{"class":3590},[3573,10504,10505,10507],{"class":3575,"line":3671},[3573,10506,4759],{"class":3586},[3573,10508,10509],{"class":3638}," \"повільний результат\"\n",[3573,10511,10512],{"class":3575,"line":3676},[3573,10513,3598],{"emptyLinePlaceholder":3597},[3573,10515,10516,10518,10520,10522],{"class":3575,"line":3695},[3573,10517,4005],{"class":3604},[3573,10519,4008],{"class":3604},[3573,10521,4161],{"class":3608},[3573,10523,5363],{"class":3590},[3573,10525,10526],{"class":3575,"line":3701},[3573,10527,10528],{"class":3579},"    # 1. Сучасний підхід: asyncio.timeout() (Python 3.11+)\n",[3573,10530,10531,10533],{"class":3575,"line":3721},[3573,10532,8471],{"class":3586},[3573,10534,3632],{"class":3590},[3573,10536,10537,10539,10541,10544,10546,10549],{"class":3575,"line":3727},[3573,10538,8483],{"class":3586},[3573,10540,8486],{"class":3586},[3573,10542,10543],{"class":3590}," asyncio.timeout(",[3573,10545,6748],{"class":4049},[3573,10547,10548],{"class":3590},"):  ",[3573,10550,10551],{"class":3579},"# таймаут на блок коду\n",[3573,10553,10554,10557,10559],{"class":3575,"line":3816},[3573,10555,10556],{"class":3590},"            result = ",[3573,10558,3488],{"class":3586},[3573,10560,10561],{"class":3590}," slow_operation()\n",[3573,10563,10564,10566],{"class":3575,"line":3822},[3573,10565,8590],{"class":3586},[3573,10567,10568],{"class":3590}," asyncio.TimeoutError:\n",[3573,10570,10571,10573,10575,10578],{"class":3575,"line":3827},[3573,10572,4113],{"class":3608},[3573,10574,3612],{"class":3590},[3573,10576,10577],{"class":3638},"\"asyncio.timeout: операція перевищила ліміт в 1s і була скасована\"",[3573,10579,3668],{"class":3590},[3573,10581,10582],{"class":3575,"line":3833},[3573,10583,3598],{"emptyLinePlaceholder":3597},[3573,10585,10586],{"class":3575,"line":3839},[3573,10587,10588],{"class":3579},"    # 2. Класичний підхід: asyncio.wait_for()\n",[3573,10590,10591,10593],{"class":3575,"line":3845},[3573,10592,8471],{"class":3586},[3573,10594,3632],{"class":3590},[3573,10596,10597,10600,10602,10605,10607,10609,10611],{"class":3575,"line":3851},[3573,10598,10599],{"class":3590},"        result = ",[3573,10601,3488],{"class":3586},[3573,10603,10604],{"class":3590}," asyncio.wait_for(slow_operation(), ",[3573,10606,7504],{"class":3615},[3573,10608,6476],{"class":3590},[3573,10610,6748],{"class":4049},[3573,10612,3668],{"class":3590},[3573,10614,10615,10617],{"class":3575,"line":3856},[3573,10616,8590],{"class":3586},[3573,10618,10568],{"class":3590},[3573,10620,10621,10623,10625,10628],{"class":3575,"line":3862},[3573,10622,4113],{"class":3608},[3573,10624,3612],{"class":3590},[3573,10626,10627],{"class":3638},"\"wait_for: операція перевищила ліміт в 1s\"",[3573,10629,3668],{"class":3590},[3573,10631,10632],{"class":3575,"line":3868},[3573,10633,3598],{"emptyLinePlaceholder":3597},[3573,10635,10636],{"class":3575,"line":3874},[3573,10637,10638],{"class":3579},"    # 3. Динамічне коригування дедлайну\n",[3573,10640,10641,10643,10645,10648,10650,10652,10654,10656,10658,10661,10663,10665,10668,10670,10672,10674],{"class":3575,"line":3880},[3573,10642,5836],{"class":3604},[3573,10644,4008],{"class":3604},[3573,10646,10647],{"class":3608}," fetch_with_retry",[3573,10649,3612],{"class":3590},[3573,10651,5710],{"class":3615},[3573,10653,3619],{"class":3590},[3573,10655,4736],{"class":3622},[3573,10657,4890],{"class":3590},[3573,10659,10660],{"class":3615},"attempts",[3573,10662,3619],{"class":3590},[3573,10664,5645],{"class":3622},[3573,10666,10667],{"class":3590}," = ",[3573,10669,4105],{"class":4049},[3573,10671,3626],{"class":3590},[3573,10673,4736],{"class":3622},[3573,10675,3632],{"class":3590},[3573,10677,10678,10680,10683,10685,10687,10689,10691,10694,10696],{"class":3575,"line":3886},[3573,10679,8024],{"class":3586},[3573,10681,10682],{"class":3590}," attempt ",[3573,10684,4097],{"class":3586},[3573,10686,4100],{"class":3608},[3573,10688,3612],{"class":3590},[3573,10690,4050],{"class":4049},[3573,10692,10693],{"class":3590},", attempts + ",[3573,10695,4050],{"class":4049},[3573,10697,4108],{"class":3590},[3573,10699,10700,10703],{"class":3575,"line":3891},[3573,10701,10702],{"class":3586},"            try",[3573,10704,3632],{"class":3590},[3573,10706,10707],{"class":3575,"line":3897},[3573,10708,10709],{"class":3579},"                # З кожною наступною спробою збільшуємо таймаут\n",[3573,10711,10712,10715,10717,10719,10721,10724,10726],{"class":3575,"line":3902},[3573,10713,10714],{"class":3586},"                async",[3573,10716,8486],{"class":3586},[3573,10718,10543],{"class":3590},[3573,10720,7724],{"class":4049},[3573,10722,10723],{"class":3590}," * attempt) ",[3573,10725,8492],{"class":3586},[3573,10727,10728],{"class":3590}," to:\n",[3573,10730,10731],{"class":3575,"line":3908},[3573,10732,10733],{"class":3579},"                    # Можливість змінити таймаут динамічно в процесі:\n",[3573,10735,10736],{"class":3575,"line":3913},[3573,10737,10738],{"class":3579},"                    # to.reschedule(loop.time() + new_delay)\n",[3573,10740,10741,10744,10746,10748,10750],{"class":3575,"line":3919},[3573,10742,10743],{"class":3586},"                    await",[3573,10745,4046],{"class":3590},[3573,10747,6773],{"class":4049},[3573,10749,4926],{"class":3590},[3573,10751,10752],{"class":3579},"# симуляція запиту\n",[3573,10754,10755,10758,10760,10763,10765,10767,10769,10772,10774,10777,10779],{"class":3575,"line":3925},[3573,10756,10757],{"class":3586},"                    return",[3573,10759,5222],{"class":3604},[3573,10761,10762],{"class":3638},"\"OK from ",[3573,10764,3656],{"class":3604},[3573,10766,5710],{"class":3590},[3573,10768,3662],{"class":3604},[3573,10770,10771],{"class":3638}," (спроба ",[3573,10773,3656],{"class":3604},[3573,10775,10776],{"class":3590},"attempt",[3573,10778,3662],{"class":3604},[3573,10780,10781],{"class":3638},")\"\n",[3573,10783,10784,10787],{"class":3575,"line":4576},[3573,10785,10786],{"class":3586},"            except",[3573,10788,10568],{"class":3590},[3573,10790,10791,10794,10796,10798,10801,10803,10805,10807,10810],{"class":3575,"line":4582},[3573,10792,10793],{"class":3608},"                print",[3573,10795,3612],{"class":3590},[3573,10797,3650],{"class":3604},[3573,10799,10800],{"class":3638},"\"  Спроба ",[3573,10802,3656],{"class":3604},[3573,10804,10776],{"class":3590},[3573,10806,3662],{"class":3604},[3573,10808,10809],{"class":3638}," перевищила таймаут\"",[3573,10811,3668],{"class":3590},[3573,10813,10814,10817,10820,10822,10824,10827,10829,10831,10833,10836],{"class":3575,"line":4588},[3573,10815,10816],{"class":3586},"        raise",[3573,10818,10819],{"class":3622}," RuntimeError",[3573,10821,3612],{"class":3590},[3573,10823,3650],{"class":3604},[3573,10825,10826],{"class":3638},"\"Всі ",[3573,10828,3656],{"class":3604},[3573,10830,10660],{"class":3590},[3573,10832,3662],{"class":3604},[3573,10834,10835],{"class":3638}," спроб завершились невдачею\"",[3573,10837,3668],{"class":3590},[3573,10839,10840],{"class":3575,"line":4593},[3573,10841,3598],{"emptyLinePlaceholder":3597},[3573,10843,10844,10846,10848,10851,10854],{"class":3575,"line":4599},[3573,10845,5368],{"class":3590},[3573,10847,3488],{"class":3586},[3573,10849,10850],{"class":3590}," fetch_with_retry(",[3573,10852,10853],{"class":3638},"\"https:\u002F\u002Fapi.example.com\"",[3573,10855,3668],{"class":3590},[3573,10857,10858,10860,10862,10864,10867,10869,10871,10873,10875],{"class":3575,"line":4604},[3573,10859,3645],{"class":3608},[3573,10861,3612],{"class":3590},[3573,10863,3650],{"class":3604},[3573,10865,10866],{"class":3638},"\"Результат: ",[3573,10868,3656],{"class":3604},[3573,10870,6021],{"class":3590},[3573,10872,3662],{"class":3604},[3573,10874,3665],{"class":3638},[3573,10876,3668],{"class":3590},[3573,10878,10879],{"class":3575,"line":4609},[3573,10880,3598],{"emptyLinePlaceholder":3597},[3573,10882,10883],{"class":3575,"line":4614},[3573,10884,4193],{"class":3590},[8639,10886,10887,10888,10890,10891,3507],{},"Завжди встановлюйте таймаути на будь-які мережеві I\u002FO запити. Без таймауту некоректно працюючий віддалений сервер може заблокувати виконання корутини нескінченно, споживаючи ресурси. ",[3438,10889,10394],{}," є пріоритетнішим вибором у Python 3.11+, оскільки він підтримує динамічне оновлення дедлайну за допомогою методу ",[3438,10892,10893],{},"Timeout.reschedule()",[3458,10895],{},[3389,10897,10899],{"id":10898},"частина-v-інтеграція-з-синхронним-кодом","Частина V: Інтеграція з синхронним кодом",[3394,10901,10902,10903,10905,10906,4313,10909,6751,10912,10915],{},"Подієвий цикл ",[3438,10904,3451],{}," за замовчуванням виконує весь код в одному системному потоці. Якщо всередині корутини викликати важку математичну операцію чи звичайну синхронну функцію, яка блокує потік (наприклад, ",[3438,10907,10908],{},"time.sleep()",[3438,10910,10911],{},"requests.get()",[3398,10913,10914],{},"весь Event Loop зупиниться",". Це призведе до заморожування всіх інших корутин, які чекають на виконання.",[3394,10917,10918,10919,10921,10922,5136],{},"Для вирішення цієї проблеми ",[3438,10920,3451],{}," надає можливість переносити блокуючі виклики в окремі системні потоки або процеси за допомогою виконавців (",[3438,10923,10924],{},"executors",[3458,10926],{},[3461,10928,10930,10933],{"id":10929},"looprun_in_executor-виконання-блокуючого-коду-без-зупинки-event-loop",[3438,10931,10932],{},"loop.run_in_executor()"," — виконання блокуючого коду без зупинки Event Loop",[3394,10935,10936,10937,10939,10940,10942,10943,3507],{},"Метод ",[3438,10938,10932],{}," запускає вказану синхронну функцію в окремому потоці або процесі з пулу, повертаючи об'єкт ",[3438,10941,4337],{},", який можна очікувати через ",[3438,10944,3488],{},[4267,10946,10948],{"id":10947},"сигнатура-методу","Сигнатура методу",[3564,10950,10952],{"className":3566,"code":10951,"language":3568,"meta":3569,"style":3569},"loop.run_in_executor(executor, func, *args)\n",[3438,10953,10954],{"__ignoreMap":3569},[3573,10955,10956],{"class":3575,"line":3576},[3573,10957,10951],{"class":3590},[5889,10959,10960,10976,10981],{},[5892,10961,10964,10965,10968,10969,10972,10973,10975],{"name":10962,"type":10963},"executor","concurrent.futures.Executor | None","Об'єкт пулу потоків (",[3438,10966,10967],{},"ThreadPoolExecutor",") або пулу процесів (",[3438,10970,10971],{},"ProcessPoolExecutor","). Якщо передано ",[3438,10974,3629],{},", використовується стандартний ThreadPoolExecutor для поточного Event Loop.",[5892,10977,10980],{"name":10978,"type":10979},"func","Callable","Синхронна функція (callable-об'єкт), яку потрібно виконати.",[5892,10982,10985,10986,10988],{"name":10983,"type":10984},"\\*args","Any","Позиційні аргументи, які будуть передані у функцію ",[3438,10987,10978],{}," при виклику.",[4267,10990,10992],{"id":10991},"threadpoolexecutor-vs-processpoolexecutor","ThreadPoolExecutor vs ProcessPoolExecutor",[3936,10994,10995,11010],{},[3425,10996,10997,11001,11002,11005,11006,11009],{},[3398,10998,10999],{},[3438,11000,10967],{}," використовується для блокуючих операцій ",[3398,11003,11004],{},"введення-виведення"," (I\u002FO-bound), таких як робота з синхронними клієнтами баз даних, запити через ",[3438,11007,11008],{},"requests"," або робота з файловою системою ОС.",[3425,11011,11012,11016],{},[3398,11013,11014],{},[3438,11015,10971],{}," використовується для важких обчислень (CPU-bound) — наприклад, обробка зображень, криптографія, парсинг великих JSON-структур. Оскільки кожен процес має власну копію інтерпретатора Python, це дозволяє обійти обмеження GIL (Global Interpreter Lock) та задіяти всі ядра процесора.",[3564,11018,11020],{"className":3566,"code":11019,"language":3568,"meta":3569,"style":3569},"# run_in_executor_demo.py\nimport asyncio\nimport time\nimport concurrent.futures\nimport urllib.request\n\n# 1. Синхронна функція введення-виведення — блокує потік\ndef blocking_http_get(url: str) -> bytes:\n    with urllib.request.urlopen(url, timeout=10) as r:\n        return r.read()\n\n# 2. Синхронна функція з важкими обчисленнями — блокує CPU\ndef blocking_cpu_work(n: int) -> int:\n    time.sleep(0.1)  # симуляція тривалої CPU-роботи\n    return sum(i * i for i in range(n))\n\nasync def main():\n    # Отримуємо об'єкт поточного Event Loop\n    loop = asyncio.get_running_loop()\n\n    # Використання ThreadPoolExecutor для I\u002FO-bound блокуючого коду\n    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as thread_pool:\n        # Запускаємо синхронний запит у пулі потоків без блокування Event Loop\n        result = await loop.run_in_executor(\n            thread_pool,\n            blocking_http_get,\n            \"https:\u002F\u002Fhttpbin.org\u002Fget\"\n        )\n        print(f\"HTTP відповідь: {len(result)} байт\")\n\n        # Конкурентний запуск кількох блокуючих I\u002FO викликів\n        urls = [\"https:\u002F\u002Fhttpbin.org\u002Fdelay\u002F0.3\"] * 5\n        tasks = [\n            loop.run_in_executor(thread_pool, blocking_http_get, url)\n            for url in urls\n        ]\n        results = await asyncio.gather(*tasks)\n        print(f\"Отримано {len(results)} відповідей конкурентно\")\n\n    # Використання ProcessPoolExecutor для CPU-bound обчислень (обхід GIL)\n    with concurrent.futures.ProcessPoolExecutor(max_workers=4) as proc_pool:\n        result = await loop.run_in_executor(\n            proc_pool,\n            blocking_cpu_work,\n            1_000_000\n        )\n        print(f\"CPU результат: {result:,}\")\n\n    # Використання стандартного ThreadPoolExecutor (якщо передати None)\n    result = await loop.run_in_executor(None, blocking_cpu_work, 500_000)\n    print(f\"Default executor: {result:,}\")\n\nasyncio.run(main())\n",[3438,11021,11022,11027,11033,11039,11046,11053,11057,11062,11083,11105,11112,11116,11121,11142,11154,11175,11179,11189,11194,11198,11202,11207,11228,11233,11242,11247,11252,11257,11262,11287,11291,11296,11310,11315,11320,11333,11338,11348,11371,11375,11380,11400,11408,11413,11418,11423,11427,11449,11453,11458,11477,11499,11504],{"__ignoreMap":3569},[3573,11023,11024],{"class":3575,"line":3576},[3573,11025,11026],{"class":3579},"# run_in_executor_demo.py\n",[3573,11028,11029,11031],{"class":3575,"line":3583},[3573,11030,3587],{"class":3586},[3573,11032,3591],{"class":3590},[3573,11034,11035,11037],{"class":3575,"line":3594},[3573,11036,3587],{"class":3586},[3573,11038,4718],{"class":3590},[3573,11040,11041,11043],{"class":3575,"line":3601},[3573,11042,3587],{"class":3586},[3573,11044,11045],{"class":3590}," concurrent.futures\n",[3573,11047,11048,11050],{"class":3575,"line":3635},[3573,11049,3587],{"class":3586},[3573,11051,11052],{"class":3590}," urllib.request\n",[3573,11054,11055],{"class":3575,"line":3642},[3573,11056,3598],{"emptyLinePlaceholder":3597},[3573,11058,11059],{"class":3575,"line":3671},[3573,11060,11061],{"class":3579},"# 1. Синхронна функція введення-виведення — блокує потік\n",[3573,11063,11064,11066,11069,11071,11073,11075,11077,11079,11081],{"class":3575,"line":3676},[3573,11065,3605],{"class":3604},[3573,11067,11068],{"class":3608}," blocking_http_get",[3573,11070,3612],{"class":3590},[3573,11072,5710],{"class":3615},[3573,11074,3619],{"class":3590},[3573,11076,4736],{"class":3622},[3573,11078,3626],{"class":3590},[3573,11080,3623],{"class":3622},[3573,11082,3632],{"class":3590},[3573,11084,11085,11088,11091,11093,11095,11097,11100,11102],{"class":3575,"line":3695},[3573,11086,11087],{"class":3586},"    with",[3573,11089,11090],{"class":3590}," urllib.request.urlopen(url, ",[3573,11092,7504],{"class":3615},[3573,11094,6476],{"class":3590},[3573,11096,8217],{"class":4049},[3573,11098,11099],{"class":3590},") ",[3573,11101,8492],{"class":3586},[3573,11103,11104],{"class":3590}," r:\n",[3573,11106,11107,11109],{"class":3575,"line":3701},[3573,11108,7265],{"class":3586},[3573,11110,11111],{"class":3590}," r.read()\n",[3573,11113,11114],{"class":3575,"line":3721},[3573,11115,3598],{"emptyLinePlaceholder":3597},[3573,11117,11118],{"class":3575,"line":3727},[3573,11119,11120],{"class":3579},"# 2. Синхронна функція з важкими обчисленнями — блокує CPU\n",[3573,11122,11123,11125,11128,11130,11132,11134,11136,11138,11140],{"class":3575,"line":3816},[3573,11124,3605],{"class":3604},[3573,11126,11127],{"class":3608}," blocking_cpu_work",[3573,11129,3612],{"class":3590},[3573,11131,5769],{"class":3615},[3573,11133,3619],{"class":3590},[3573,11135,5645],{"class":3622},[3573,11137,3626],{"class":3590},[3573,11139,5645],{"class":3622},[3573,11141,3632],{"class":3590},[3573,11143,11144,11147,11149,11151],{"class":3575,"line":3822},[3573,11145,11146],{"class":3590},"    time.sleep(",[3573,11148,5213],{"class":4049},[3573,11150,4926],{"class":3590},[3573,11152,11153],{"class":3579},"# симуляція тривалої CPU-роботи\n",[3573,11155,11156,11158,11161,11164,11166,11168,11170,11172],{"class":3575,"line":3827},[3573,11157,4759],{"class":3586},[3573,11159,11160],{"class":3608}," sum",[3573,11162,11163],{"class":3590},"(i * i ",[3573,11165,5580],{"class":3586},[3573,11167,4094],{"class":3590},[3573,11169,4097],{"class":3586},[3573,11171,4100],{"class":3608},[3573,11173,11174],{"class":3590},"(n))\n",[3573,11176,11177],{"class":3575,"line":3833},[3573,11178,3598],{"emptyLinePlaceholder":3597},[3573,11180,11181,11183,11185,11187],{"class":3575,"line":3839},[3573,11182,4005],{"class":3604},[3573,11184,4008],{"class":3604},[3573,11186,4161],{"class":3608},[3573,11188,5363],{"class":3590},[3573,11190,11191],{"class":3575,"line":3845},[3573,11192,11193],{"class":3579},"    # Отримуємо об'єкт поточного Event Loop\n",[3573,11195,11196],{"class":3575,"line":3851},[3573,11197,6102],{"class":3590},[3573,11199,11200],{"class":3575,"line":3856},[3573,11201,3598],{"emptyLinePlaceholder":3597},[3573,11203,11204],{"class":3575,"line":3862},[3573,11205,11206],{"class":3579},"    # Використання ThreadPoolExecutor для I\u002FO-bound блокуючого коду\n",[3573,11208,11209,11211,11214,11217,11219,11221,11223,11225],{"class":3575,"line":3868},[3573,11210,11087],{"class":3586},[3573,11212,11213],{"class":3590}," concurrent.futures.ThreadPoolExecutor(",[3573,11215,11216],{"class":3615},"max_workers",[3573,11218,6476],{"class":3590},[3573,11220,5850],{"class":4049},[3573,11222,11099],{"class":3590},[3573,11224,8492],{"class":3586},[3573,11226,11227],{"class":3590}," thread_pool:\n",[3573,11229,11230],{"class":3575,"line":3874},[3573,11231,11232],{"class":3579},"        # Запускаємо синхронний запит у пулі потоків без блокування Event Loop\n",[3573,11234,11235,11237,11239],{"class":3575,"line":3880},[3573,11236,10599],{"class":3590},[3573,11238,3488],{"class":3586},[3573,11240,11241],{"class":3590}," loop.run_in_executor(\n",[3573,11243,11244],{"class":3575,"line":3886},[3573,11245,11246],{"class":3590},"            thread_pool,\n",[3573,11248,11249],{"class":3575,"line":3891},[3573,11250,11251],{"class":3590},"            blocking_http_get,\n",[3573,11253,11254],{"class":3575,"line":3897},[3573,11255,11256],{"class":3638},"            \"https:\u002F\u002Fhttpbin.org\u002Fget\"\n",[3573,11258,11259],{"class":3575,"line":3902},[3573,11260,11261],{"class":3590},"        )\n",[3573,11263,11264,11266,11268,11270,11273,11275,11277,11280,11282,11285],{"class":3575,"line":3908},[3573,11265,4113],{"class":3608},[3573,11267,3612],{"class":3590},[3573,11269,3650],{"class":3604},[3573,11271,11272],{"class":3638},"\"HTTP відповідь: ",[3573,11274,3656],{"class":3604},[3573,11276,7816],{"class":3608},[3573,11278,11279],{"class":3590},"(result)",[3573,11281,3662],{"class":3604},[3573,11283,11284],{"class":3638}," байт\"",[3573,11286,3668],{"class":3590},[3573,11288,11289],{"class":3575,"line":3913},[3573,11290,3598],{"emptyLinePlaceholder":3597},[3573,11292,11293],{"class":3575,"line":3919},[3573,11294,11295],{"class":3579},"        # Конкурентний запуск кількох блокуючих I\u002FO викликів\n",[3573,11297,11298,11301,11304,11307],{"class":3575,"line":3925},[3573,11299,11300],{"class":3590},"        urls = [",[3573,11302,11303],{"class":3638},"\"https:\u002F\u002Fhttpbin.org\u002Fdelay\u002F0.3\"",[3573,11305,11306],{"class":3590},"] * ",[3573,11308,11309],{"class":4049},"5\n",[3573,11311,11312],{"class":3575,"line":4576},[3573,11313,11314],{"class":3590},"        tasks = [\n",[3573,11316,11317],{"class":3575,"line":4582},[3573,11318,11319],{"class":3590},"            loop.run_in_executor(thread_pool, blocking_http_get, url)\n",[3573,11321,11322,11325,11328,11330],{"class":3575,"line":4588},[3573,11323,11324],{"class":3586},"            for",[3573,11326,11327],{"class":3590}," url ",[3573,11329,4097],{"class":3586},[3573,11331,11332],{"class":3590}," urls\n",[3573,11334,11335],{"class":3575,"line":4593},[3573,11336,11337],{"class":3590},"        ]\n",[3573,11339,11340,11343,11345],{"class":3575,"line":4599},[3573,11341,11342],{"class":3590},"        results = ",[3573,11344,3488],{"class":3586},[3573,11346,11347],{"class":3590}," asyncio.gather(*tasks)\n",[3573,11349,11350,11352,11354,11356,11358,11360,11362,11364,11366,11369],{"class":3575,"line":4604},[3573,11351,4113],{"class":3608},[3573,11353,3612],{"class":3590},[3573,11355,3650],{"class":3604},[3573,11357,7158],{"class":3638},[3573,11359,3656],{"class":3604},[3573,11361,7816],{"class":3608},[3573,11363,9397],{"class":3590},[3573,11365,3662],{"class":3604},[3573,11367,11368],{"class":3638}," відповідей конкурентно\"",[3573,11370,3668],{"class":3590},[3573,11372,11373],{"class":3575,"line":4609},[3573,11374,3598],{"emptyLinePlaceholder":3597},[3573,11376,11377],{"class":3575,"line":4614},[3573,11378,11379],{"class":3579},"    # Використання ProcessPoolExecutor для CPU-bound обчислень (обхід GIL)\n",[3573,11381,11382,11384,11387,11389,11391,11393,11395,11397],{"class":3575,"line":4620},[3573,11383,11087],{"class":3586},[3573,11385,11386],{"class":3590}," concurrent.futures.ProcessPoolExecutor(",[3573,11388,11216],{"class":3615},[3573,11390,6476],{"class":3590},[3573,11392,9603],{"class":4049},[3573,11394,11099],{"class":3590},[3573,11396,8492],{"class":3586},[3573,11398,11399],{"class":3590}," proc_pool:\n",[3573,11401,11402,11404,11406],{"class":3575,"line":4626},[3573,11403,10599],{"class":3590},[3573,11405,3488],{"class":3586},[3573,11407,11241],{"class":3590},[3573,11409,11410],{"class":3575,"line":4631},[3573,11411,11412],{"class":3590},"            proc_pool,\n",[3573,11414,11415],{"class":3575,"line":4636},[3573,11416,11417],{"class":3590},"            blocking_cpu_work,\n",[3573,11419,11420],{"class":3575,"line":4642},[3573,11421,11422],{"class":4049},"            1_000_000\n",[3573,11424,11425],{"class":3575,"line":4647},[3573,11426,11261],{"class":3590},[3573,11428,11429,11431,11433,11435,11438,11440,11442,11445,11447],{"class":3575,"line":4653},[3573,11430,4113],{"class":3608},[3573,11432,3612],{"class":3590},[3573,11434,3650],{"class":3604},[3573,11436,11437],{"class":3638},"\"CPU результат: ",[3573,11439,3656],{"class":3604},[3573,11441,6021],{"class":3590},[3573,11443,11444],{"class":3604},":,}",[3573,11446,3665],{"class":3638},[3573,11448,3668],{"class":3590},[3573,11450,11451],{"class":3575,"line":4658},[3573,11452,3598],{"emptyLinePlaceholder":3597},[3573,11454,11455],{"class":3575,"line":4664},[3573,11456,11457],{"class":3579},"    # Використання стандартного ThreadPoolExecutor (якщо передати None)\n",[3573,11459,11460,11462,11464,11467,11469,11472,11475],{"class":3575,"line":4669},[3573,11461,5368],{"class":3590},[3573,11463,3488],{"class":3586},[3573,11465,11466],{"class":3590}," loop.run_in_executor(",[3573,11468,3629],{"class":3604},[3573,11470,11471],{"class":3590},", blocking_cpu_work, ",[3573,11473,11474],{"class":4049},"500_000",[3573,11476,3668],{"class":3590},[3573,11478,11480,11482,11484,11486,11489,11491,11493,11495,11497],{"class":3575,"line":11479},51,[3573,11481,3645],{"class":3608},[3573,11483,3612],{"class":3590},[3573,11485,3650],{"class":3604},[3573,11487,11488],{"class":3638},"\"Default executor: ",[3573,11490,3656],{"class":3604},[3573,11492,6021],{"class":3590},[3573,11494,11444],{"class":3604},[3573,11496,3665],{"class":3638},[3573,11498,3668],{"class":3590},[3573,11500,11502],{"class":3575,"line":11501},52,[3573,11503,3598],{"emptyLinePlaceholder":3597},[3573,11505,11507],{"class":3575,"line":11506},53,[3573,11508,4193],{"class":3590},[8639,11510,11511,11512,11515,11516,8644,11519,4890,11521,8644,11524,11527],{},"Намагайтеся не використовувати ",[3438,11513,11514],{},"run_in_executor()"," для нових розробок, якщо існують готові асинхронні аналоги (наприклад, ",[3438,11517,11518],{},"httpx",[3438,11520,11008],{},[3438,11522,11523],{},"asyncpg",[3438,11525,11526],{},"psycopg2","). Використовуйте ексекутори лише для інтеграції legacy-коду або для перенесення обчислювальних завдань на процеси.",[3458,11529],{},[3389,11531,11533],{"id":11532},"частина-vi-типові-антипатерни-asyncio","Частина VI: Типові антипатерни asyncio",[3394,11535,11536],{},"Навіть досвідчені розробники при переході на асинхронну модель допускають помилки, які нівелюють переваги асинхронності або призводять до падіння додатку.",[3461,11538,11540],{"id":11539},"антипатерн-1-блокуючий-виклик-всередині-корутини","Антипатерн 1: Блокуючий виклик всередині корутини",[3394,11542,11543],{},"Найбільш поширена помилка. Використання синхронної бібліотеки всередині корутини повністю зупиняє весь процес обробки подій Event Loop.",[3564,11545,11547],{"className":3566,"code":11546,"language":3568,"meta":3569,"style":3569},"import asyncio\nimport time\nimport requests  # синхронна бібліотека запитів\n\nasync def bad_fetch(url: str) -> bytes:\n    # ❌ НЕПРАВИЛЬНО: requests.get заблокує Event Loop для всіх інших задач!\n    response = requests.get(url)\n    return response.content\n\nasync def good_fetch(url: str) -> bytes:\n    # ✅ ПРАВИЛЬНО варіант 1: використовувати асинхронну бібліотеку (наприклад, httpx)\n    # import httpx\n    # async with httpx.AsyncClient() as client:\n    #     resp = await client.get(url)\n    #     return resp.content\n\n    # ✅ ПРАВИЛЬНО варіант 2: винести блокуючий запит у ThreadPoolExecutor\n    import concurrent.futures\n    loop = asyncio.get_running_loop()\n    with concurrent.futures.ThreadPoolExecutor() as pool:\n        return await loop.run_in_executor(pool, requests.get, url)\n",[3438,11548,11549,11555,11561,11571,11575,11598,11603,11608,11615,11619,11642,11647,11652,11657,11662,11667,11671,11676,11683,11687,11699],{"__ignoreMap":3569},[3573,11550,11551,11553],{"class":3575,"line":3576},[3573,11552,3587],{"class":3586},[3573,11554,3591],{"class":3590},[3573,11556,11557,11559],{"class":3575,"line":3583},[3573,11558,3587],{"class":3586},[3573,11560,4718],{"class":3590},[3573,11562,11563,11565,11568],{"class":3575,"line":3594},[3573,11564,3587],{"class":3586},[3573,11566,11567],{"class":3590}," requests  ",[3573,11569,11570],{"class":3579},"# синхронна бібліотека запитів\n",[3573,11572,11573],{"class":3575,"line":3601},[3573,11574,3598],{"emptyLinePlaceholder":3597},[3573,11576,11577,11579,11581,11584,11586,11588,11590,11592,11594,11596],{"class":3575,"line":3635},[3573,11578,4005],{"class":3604},[3573,11580,4008],{"class":3604},[3573,11582,11583],{"class":3608}," bad_fetch",[3573,11585,3612],{"class":3590},[3573,11587,5710],{"class":3615},[3573,11589,3619],{"class":3590},[3573,11591,4736],{"class":3622},[3573,11593,3626],{"class":3590},[3573,11595,3623],{"class":3622},[3573,11597,3632],{"class":3590},[3573,11599,11600],{"class":3575,"line":3642},[3573,11601,11602],{"class":3579},"    # ❌ НЕПРАВИЛЬНО: requests.get заблокує Event Loop для всіх інших задач!\n",[3573,11604,11605],{"class":3575,"line":3671},[3573,11606,11607],{"class":3590},"    response = requests.get(url)\n",[3573,11609,11610,11612],{"class":3575,"line":3676},[3573,11611,4759],{"class":3586},[3573,11613,11614],{"class":3590}," response.content\n",[3573,11616,11617],{"class":3575,"line":3695},[3573,11618,3598],{"emptyLinePlaceholder":3597},[3573,11620,11621,11623,11625,11628,11630,11632,11634,11636,11638,11640],{"class":3575,"line":3701},[3573,11622,4005],{"class":3604},[3573,11624,4008],{"class":3604},[3573,11626,11627],{"class":3608}," good_fetch",[3573,11629,3612],{"class":3590},[3573,11631,5710],{"class":3615},[3573,11633,3619],{"class":3590},[3573,11635,4736],{"class":3622},[3573,11637,3626],{"class":3590},[3573,11639,3623],{"class":3622},[3573,11641,3632],{"class":3590},[3573,11643,11644],{"class":3575,"line":3721},[3573,11645,11646],{"class":3579},"    # ✅ ПРАВИЛЬНО варіант 1: використовувати асинхронну бібліотеку (наприклад, httpx)\n",[3573,11648,11649],{"class":3575,"line":3727},[3573,11650,11651],{"class":3579},"    # import httpx\n",[3573,11653,11654],{"class":3575,"line":3816},[3573,11655,11656],{"class":3579},"    # async with httpx.AsyncClient() as client:\n",[3573,11658,11659],{"class":3575,"line":3822},[3573,11660,11661],{"class":3579},"    #     resp = await client.get(url)\n",[3573,11663,11664],{"class":3575,"line":3827},[3573,11665,11666],{"class":3579},"    #     return resp.content\n",[3573,11668,11669],{"class":3575,"line":3833},[3573,11670,3598],{"emptyLinePlaceholder":3597},[3573,11672,11673],{"class":3575,"line":3839},[3573,11674,11675],{"class":3579},"    # ✅ ПРАВИЛЬНО варіант 2: винести блокуючий запит у ThreadPoolExecutor\n",[3573,11677,11678,11681],{"class":3575,"line":3845},[3573,11679,11680],{"class":3586},"    import",[3573,11682,11045],{"class":3590},[3573,11684,11685],{"class":3575,"line":3851},[3573,11686,6102],{"class":3590},[3573,11688,11689,11691,11694,11696],{"class":3575,"line":3856},[3573,11690,11087],{"class":3586},[3573,11692,11693],{"class":3590}," concurrent.futures.ThreadPoolExecutor() ",[3573,11695,8492],{"class":3586},[3573,11697,11698],{"class":3590}," pool:\n",[3573,11700,11701,11703,11706],{"class":3575,"line":3862},[3573,11702,7265],{"class":3586},[3573,11704,11705],{"class":3586}," await",[3573,11707,11708],{"class":3590}," loop.run_in_executor(pool, requests.get, url)\n",[3461,11710,11712,11713],{"id":11711},"антипатерн-2-забутий-await","Антипатерн 2: Забутий ",[3438,11714,3488],{},[3394,11716,11717,11718,11720],{},"Спроба викликати асинхронну корутину як звичайну функцію без оператора ",[3438,11719,3488],{}," призводить до того, що повертається не результат обчислення, а сам об'єкт корутини.",[3564,11722,11724],{"className":3566,"code":11723,"language":3568,"meta":3569,"style":3569},"import asyncio\n\nasync def fetch_data() -> dict:\n    await asyncio.sleep(0.1)\n    return {\"key\": \"value\"}\n\nasync def bad_main():\n    # ❌ НЕПРАВИЛЬНО: повертається об'єкт корутини, а не словник\n    data = fetch_data()\n    # Спроба звернутися за ключем викликає помилку:\n    # TypeError: 'coroutine' object is not subscriptable\n    print(data[\"key\"])\n    # Також Python згенерує попередження:\n    # RuntimeWarning: coroutine 'fetch_data' was never awaited\n\nasync def good_main():\n    # ✅ ПРАВИЛЬНО: обов'язкове очікування результату\n    data = await fetch_data()\n    print(data[\"key\"])\n",[3438,11725,11726,11732,11736,11752,11762,11780,11784,11795,11800,11805,11810,11815,11826,11831,11836,11840,11851,11856,11866],{"__ignoreMap":3569},[3573,11727,11728,11730],{"class":3575,"line":3576},[3573,11729,3587],{"class":3586},[3573,11731,3591],{"class":3590},[3573,11733,11734],{"class":3575,"line":3583},[3573,11735,3598],{"emptyLinePlaceholder":3597},[3573,11737,11738,11740,11742,11745,11747,11750],{"class":3575,"line":3594},[3573,11739,4005],{"class":3604},[3573,11741,4008],{"class":3604},[3573,11743,11744],{"class":3608}," fetch_data",[3573,11746,4014],{"class":3590},[3573,11748,11749],{"class":3622},"dict",[3573,11751,3632],{"class":3590},[3573,11753,11754,11756,11758,11760],{"class":3575,"line":3601},[3573,11755,4043],{"class":3586},[3573,11757,4046],{"class":3590},[3573,11759,5213],{"class":4049},[3573,11761,3668],{"class":3590},[3573,11763,11764,11766,11769,11772,11774,11777],{"class":3575,"line":3635},[3573,11765,4759],{"class":3586},[3573,11767,11768],{"class":3590}," {",[3573,11770,11771],{"class":3638},"\"key\"",[3573,11773,3619],{"class":3590},[3573,11775,11776],{"class":3638},"\"value\"",[3573,11778,11779],{"class":3590},"}\n",[3573,11781,11782],{"class":3575,"line":3642},[3573,11783,3598],{"emptyLinePlaceholder":3597},[3573,11785,11786,11788,11790,11793],{"class":3575,"line":3671},[3573,11787,4005],{"class":3604},[3573,11789,4008],{"class":3604},[3573,11791,11792],{"class":3608}," bad_main",[3573,11794,5363],{"class":3590},[3573,11796,11797],{"class":3575,"line":3676},[3573,11798,11799],{"class":3579},"    # ❌ НЕПРАВИЛЬНО: повертається об'єкт корутини, а не словник\n",[3573,11801,11802],{"class":3575,"line":3695},[3573,11803,11804],{"class":3590},"    data = fetch_data()\n",[3573,11806,11807],{"class":3575,"line":3701},[3573,11808,11809],{"class":3579},"    # Спроба звернутися за ключем викликає помилку:\n",[3573,11811,11812],{"class":3575,"line":3721},[3573,11813,11814],{"class":3579},"    # TypeError: 'coroutine' object is not subscriptable\n",[3573,11816,11817,11819,11822,11824],{"class":3575,"line":3727},[3573,11818,3645],{"class":3608},[3573,11820,11821],{"class":3590},"(data[",[3573,11823,11771],{"class":3638},[3573,11825,9610],{"class":3590},[3573,11827,11828],{"class":3575,"line":3816},[3573,11829,11830],{"class":3579},"    # Також Python згенерує попередження:\n",[3573,11832,11833],{"class":3575,"line":3822},[3573,11834,11835],{"class":3579},"    # RuntimeWarning: coroutine 'fetch_data' was never awaited\n",[3573,11837,11838],{"class":3575,"line":3827},[3573,11839,3598],{"emptyLinePlaceholder":3597},[3573,11841,11842,11844,11846,11849],{"class":3575,"line":3833},[3573,11843,4005],{"class":3604},[3573,11845,4008],{"class":3604},[3573,11847,11848],{"class":3608}," good_main",[3573,11850,5363],{"class":3590},[3573,11852,11853],{"class":3575,"line":3839},[3573,11854,11855],{"class":3579},"    # ✅ ПРАВИЛЬНО: обов'язкове очікування результату\n",[3573,11857,11858,11861,11863],{"class":3575,"line":3845},[3573,11859,11860],{"class":3590},"    data = ",[3573,11862,3488],{"class":3586},[3573,11864,11865],{"class":3590}," fetch_data()\n",[3573,11867,11868,11870,11872,11874],{"class":3575,"line":3851},[3573,11869,3645],{"class":3608},[3573,11871,11821],{"class":3590},[3573,11873,11771],{"class":3638},[3573,11875,9610],{"class":3590},[3461,11877,11879,11880,11882],{"id":11878},"антипатерн-3-послідовний-await-замість-конкурентного-виконання","Антипатерн 3: Послідовний ",[3438,11881,3488],{}," замість конкурентного виконання",[3394,11884,11885,11886,11888],{},"Якщо перед кожним викликом корутини стоїть ",[3438,11887,3488],{},", корутини виконуються послідовно одна за одною, а не конкурентно.",[3564,11890,11892],{"className":3566,"code":11891,"language":3568,"meta":3569,"style":3569},"import asyncio\n\nasync def fetch(n: int) -> int:\n    await asyncio.sleep(1.0)\n    return n\n\nasync def bad_concurrent():\n    # ❌ НЕПРАВИЛЬНО: кожна наступна задача чекає на завершення попередньої.\n    # Загальний час виконання складе ~3 секунди.\n    r1 = await fetch(1)\n    r2 = await fetch(2)\n    r3 = await fetch(3)\n    return [r1, r2, r3]\n\nasync def good_concurrent():\n    # ✅ ПРАВИЛЬНО: gather запускає корутини одночасно в чергу Event Loop.\n    # Загальний час виконання складе ~1 секунду.\n    return await asyncio.gather(fetch(1), fetch(2), fetch(3))\n",[3438,11893,11894,11900,11904,11926,11936,11943,11947,11958,11963,11968,11981,11993,12005,12012,12016,12027,12032,12037],{"__ignoreMap":3569},[3573,11895,11896,11898],{"class":3575,"line":3576},[3573,11897,3587],{"class":3586},[3573,11899,3591],{"class":3590},[3573,11901,11902],{"class":3575,"line":3583},[3573,11903,3598],{"emptyLinePlaceholder":3597},[3573,11905,11906,11908,11910,11912,11914,11916,11918,11920,11922,11924],{"class":3575,"line":3594},[3573,11907,4005],{"class":3604},[3573,11909,4008],{"class":3604},[3573,11911,7012],{"class":3608},[3573,11913,3612],{"class":3590},[3573,11915,5769],{"class":3615},[3573,11917,3619],{"class":3590},[3573,11919,5645],{"class":3622},[3573,11921,3626],{"class":3590},[3573,11923,5645],{"class":3622},[3573,11925,3632],{"class":3590},[3573,11927,11928,11930,11932,11934],{"class":3575,"line":3601},[3573,11929,4043],{"class":3586},[3573,11931,4046],{"class":3590},[3573,11933,6748],{"class":4049},[3573,11935,3668],{"class":3590},[3573,11937,11938,11940],{"class":3575,"line":3635},[3573,11939,4759],{"class":3586},[3573,11941,11942],{"class":3590}," n\n",[3573,11944,11945],{"class":3575,"line":3642},[3573,11946,3598],{"emptyLinePlaceholder":3597},[3573,11948,11949,11951,11953,11956],{"class":3575,"line":3671},[3573,11950,4005],{"class":3604},[3573,11952,4008],{"class":3604},[3573,11954,11955],{"class":3608}," bad_concurrent",[3573,11957,5363],{"class":3590},[3573,11959,11960],{"class":3575,"line":3676},[3573,11961,11962],{"class":3579},"    # ❌ НЕПРАВИЛЬНО: кожна наступна задача чекає на завершення попередньої.\n",[3573,11964,11965],{"class":3575,"line":3695},[3573,11966,11967],{"class":3579},"    # Загальний час виконання складе ~3 секунди.\n",[3573,11969,11970,11972,11974,11977,11979],{"class":3575,"line":3701},[3573,11971,4849],{"class":3590},[3573,11973,3488],{"class":3586},[3573,11975,11976],{"class":3590}," fetch(",[3573,11978,4050],{"class":4049},[3573,11980,3668],{"class":3590},[3573,11982,11983,11985,11987,11989,11991],{"class":3575,"line":3721},[3573,11984,4864],{"class":3590},[3573,11986,3488],{"class":3586},[3573,11988,11976],{"class":3590},[3573,11990,9594],{"class":4049},[3573,11992,3668],{"class":3590},[3573,11994,11995,11997,11999,12001,12003],{"class":3575,"line":3727},[3573,11996,6840],{"class":3590},[3573,11998,3488],{"class":3586},[3573,12000,11976],{"class":3590},[3573,12002,4105],{"class":4049},[3573,12004,3668],{"class":3590},[3573,12006,12007,12009],{"class":3575,"line":3816},[3573,12008,4759],{"class":3586},[3573,12010,12011],{"class":3590}," [r1, r2, r3]\n",[3573,12013,12014],{"class":3575,"line":3822},[3573,12015,3598],{"emptyLinePlaceholder":3597},[3573,12017,12018,12020,12022,12025],{"class":3575,"line":3827},[3573,12019,4005],{"class":3604},[3573,12021,4008],{"class":3604},[3573,12023,12024],{"class":3608}," good_concurrent",[3573,12026,5363],{"class":3590},[3573,12028,12029],{"class":3575,"line":3833},[3573,12030,12031],{"class":3579},"    # ✅ ПРАВИЛЬНО: gather запускає корутини одночасно в чергу Event Loop.\n",[3573,12033,12034],{"class":3575,"line":3839},[3573,12035,12036],{"class":3579},"    # Загальний час виконання складе ~1 секунду.\n",[3573,12038,12039,12041,12043,12046,12048,12051,12053,12055,12057],{"class":3575,"line":3845},[3573,12040,4759],{"class":3586},[3573,12042,11705],{"class":3586},[3573,12044,12045],{"class":3590}," asyncio.gather(fetch(",[3573,12047,4050],{"class":4049},[3573,12049,12050],{"class":3590},"), fetch(",[3573,12052,9594],{"class":4049},[3573,12054,12050],{"class":3590},[3573,12056,4105],{"class":4049},[3573,12058,5333],{"class":3590},[3461,12060,12062,12063,12065],{"id":12061},"антипатерн-4-виклик-asynciorun-у-вже-запущеному-event-loop","Антипатерн 4: Виклик ",[3438,12064,6184],{}," у вже запущеному Event Loop",[3394,12067,12068],{},"Спроба створити новий Event Loop там, де один вже активний, завершиться критичною помилкою.",[3564,12070,12072],{"className":3566,"code":12071,"language":3568,"meta":3569,"style":3569},"import asyncio\n\nasync def inner() -> str:\n    return \"result\"\n\nasync def outer():\n    # ❌ НЕПРАВИЛЬНО: викликати asyncio.run() всередині активного циклу подій.\n    # Призведе до: RuntimeError: This event loop is already running\n    result = asyncio.run(inner())\n\n    # ✅ ПРАВИЛЬНО: просто чекати виконання корутини\n    result = await inner()\n    return result\n",[3438,12073,12074,12080,12084,12099,12106,12110,12121,12126,12131,12136,12140,12145,12154],{"__ignoreMap":3569},[3573,12075,12076,12078],{"class":3575,"line":3576},[3573,12077,3587],{"class":3586},[3573,12079,3591],{"class":3590},[3573,12081,12082],{"class":3575,"line":3583},[3573,12083,3598],{"emptyLinePlaceholder":3597},[3573,12085,12086,12088,12090,12093,12095,12097],{"class":3575,"line":3594},[3573,12087,4005],{"class":3604},[3573,12089,4008],{"class":3604},[3573,12091,12092],{"class":3608}," inner",[3573,12094,4014],{"class":3590},[3573,12096,4736],{"class":3622},[3573,12098,3632],{"class":3590},[3573,12100,12101,12103],{"class":3575,"line":3601},[3573,12102,4759],{"class":3586},[3573,12104,12105],{"class":3638}," \"result\"\n",[3573,12107,12108],{"class":3575,"line":3635},[3573,12109,3598],{"emptyLinePlaceholder":3597},[3573,12111,12112,12114,12116,12119],{"class":3575,"line":3642},[3573,12113,4005],{"class":3604},[3573,12115,4008],{"class":3604},[3573,12117,12118],{"class":3608}," outer",[3573,12120,5363],{"class":3590},[3573,12122,12123],{"class":3575,"line":3671},[3573,12124,12125],{"class":3579},"    # ❌ НЕПРАВИЛЬНО: викликати asyncio.run() всередині активного циклу подій.\n",[3573,12127,12128],{"class":3575,"line":3676},[3573,12129,12130],{"class":3579},"    # Призведе до: RuntimeError: This event loop is already running\n",[3573,12132,12133],{"class":3575,"line":3695},[3573,12134,12135],{"class":3590},"    result = asyncio.run(inner())\n",[3573,12137,12138],{"class":3575,"line":3701},[3573,12139,3598],{"emptyLinePlaceholder":3597},[3573,12141,12142],{"class":3575,"line":3721},[3573,12143,12144],{"class":3579},"    # ✅ ПРАВИЛЬНО: просто чекати виконання корутини\n",[3573,12146,12147,12149,12151],{"class":3575,"line":3727},[3573,12148,5368],{"class":3590},[3573,12150,3488],{"class":3586},[3573,12152,12153],{"class":3590}," inner()\n",[3573,12155,12156,12158],{"class":3575,"line":3816},[3573,12157,4759],{"class":3586},[3573,12159,12160],{"class":3590}," result\n",[3461,12162,12164],{"id":12163},"антипатерн-5-створення-корутин-без-запуску","Антипатерн 5: Створення корутин без запуску",[3394,12166,12167,12168,12170,12171,3507],{},"Створення об'єктів корутин та ігнорування їх без виклику ",[3438,12169,3488],{}," або планування через ",[3438,12172,12173],{},"create_task()",[3564,12175,12177],{"className":3566,"code":12176,"language":3568,"meta":3569,"style":3569},"import asyncio\n\nasync def important_work() -> None:\n    print(\"Виконую важливу роботу!\")\n\nasync def main():\n    # ❌ НЕПРАВИЛЬНО: корутину створено, але не запущено. Вона просто зникне при виході.\n    # Python згенерує попередження: RuntimeWarning: coroutine 'important_work' was never awaited\n    coro = important_work()\n\n    # ✅ ПРАВИЛЬНО:\n    await important_work()\n\n    # Або запуск у фоні Event Loop:\n    task = asyncio.create_task(important_work())\n    await task\n",[3438,12178,12179,12185,12189,12204,12215,12219,12229,12234,12239,12244,12248,12253,12260,12264,12269,12274],{"__ignoreMap":3569},[3573,12180,12181,12183],{"class":3575,"line":3576},[3573,12182,3587],{"class":3586},[3573,12184,3591],{"class":3590},[3573,12186,12187],{"class":3575,"line":3583},[3573,12188,3598],{"emptyLinePlaceholder":3597},[3573,12190,12191,12193,12195,12198,12200,12202],{"class":3575,"line":3594},[3573,12192,4005],{"class":3604},[3573,12194,4008],{"class":3604},[3573,12196,12197],{"class":3608}," important_work",[3573,12199,4014],{"class":3590},[3573,12201,3629],{"class":3604},[3573,12203,3632],{"class":3590},[3573,12205,12206,12208,12210,12213],{"class":3575,"line":3601},[3573,12207,3645],{"class":3608},[3573,12209,3612],{"class":3590},[3573,12211,12212],{"class":3638},"\"Виконую важливу роботу!\"",[3573,12214,3668],{"class":3590},[3573,12216,12217],{"class":3575,"line":3635},[3573,12218,3598],{"emptyLinePlaceholder":3597},[3573,12220,12221,12223,12225,12227],{"class":3575,"line":3642},[3573,12222,4005],{"class":3604},[3573,12224,4008],{"class":3604},[3573,12226,4161],{"class":3608},[3573,12228,5363],{"class":3590},[3573,12230,12231],{"class":3575,"line":3671},[3573,12232,12233],{"class":3579},"    # ❌ НЕПРАВИЛЬНО: корутину створено, але не запущено. Вона просто зникне при виході.\n",[3573,12235,12236],{"class":3575,"line":3676},[3573,12237,12238],{"class":3579},"    # Python згенерує попередження: RuntimeWarning: coroutine 'important_work' was never awaited\n",[3573,12240,12241],{"class":3575,"line":3695},[3573,12242,12243],{"class":3590},"    coro = important_work()\n",[3573,12245,12246],{"class":3575,"line":3701},[3573,12247,3598],{"emptyLinePlaceholder":3597},[3573,12249,12250],{"class":3575,"line":3721},[3573,12251,12252],{"class":3579},"    # ✅ ПРАВИЛЬНО:\n",[3573,12254,12255,12257],{"class":3575,"line":3727},[3573,12256,4043],{"class":3586},[3573,12258,12259],{"class":3590}," important_work()\n",[3573,12261,12262],{"class":3575,"line":3816},[3573,12263,3598],{"emptyLinePlaceholder":3597},[3573,12265,12266],{"class":3575,"line":3822},[3573,12267,12268],{"class":3579},"    # Або запуск у фоні Event Loop:\n",[3573,12270,12271],{"class":3575,"line":3827},[3573,12272,12273],{"class":3590},"    task = asyncio.create_task(important_work())\n",[3573,12275,12276,12278],{"class":3575,"line":3833},[3573,12277,4043],{"class":3586},[3573,12279,12280],{"class":3590}," task\n",[3458,12282],{},[3389,12284,12286],{"id":12285},"частина-vii-реальний-патерн-асинхронний-веб-скрапер","Частина VII: Реальний патерн — асинхронний веб-скрапер",[3394,12288,12289,12290,12293,12294,12296,12297,12300],{},"Об'єднаємо всі вивчені інструменти (обмеження конкурентності за допомогою ",[3438,12291,12292],{},"Semaphore",", інтеграція синхронного коду через ",[3438,12295,3506],{},", встановлення таймаутів ",[3438,12298,12299],{},"asyncio.timeout",", обробка виключень та експоненціальна затримка) в одному реальному додатку — веб-скрапері.",[3564,12302,12304],{"className":3566,"code":12303,"language":3568,"meta":3569,"style":3569},"# async_scraper.py\nfrom __future__ import annotations\n\nimport asyncio\nimport time\nimport urllib.request\nfrom dataclasses import dataclass, field\nfrom collections import defaultdict\nimport concurrent.futures\n\n@dataclass\nclass ScrapeResult:\n    url: str\n    success: bool\n    status_code: int = 0\n    size_bytes: int = 0\n    elapsed: float = 0.0\n    attempts: int = 0\n    error: str = \"\"\n\n@dataclass\nclass ScraperStats:\n    total: int = 0\n    successful: int = 0\n    failed: int = 0\n    total_bytes: int = 0\n    total_time: float = 0.0\n    errors: dict[str, int] = field(default_factory=lambda: defaultdict(int))\n\ndef _sync_fetch(url: str) -> tuple[int, bytes]:\n    \"\"\"Синхронний мережевий запит для виконання у пулі потоків.\"\"\"\n    with urllib.request.urlopen(url, timeout=10) as r:\n        return r.status, r.read()\n\nasync def fetch_url(\n    url: str,\n    semaphore: asyncio.Semaphore,\n    executor: concurrent.futures.ThreadPoolExecutor,\n    max_retries: int = 3,\n    retry_delay: float = 0.5,\n) -> ScrapeResult:\n    \"\"\"Завантажує URL з обмеженням конкурентності, таймаутом і повторними спробами.\"\"\"\n    loop = asyncio.get_running_loop()\n    start = time.perf_counter()\n\n    for attempt in range(1, max_retries + 1):\n        async with semaphore:    # Обмежуємо кількість одночасних запитів\n            try:\n                # Встановлюємо жорсткий таймаут на виконання всього запиту\n                async with asyncio.timeout(8.0):\n                    status, data = await loop.run_in_executor(\n                        executor, _sync_fetch, url\n                    )\n                elapsed = time.perf_counter() - start\n                return ScrapeResult(\n                    url=url,\n                    success=True,\n                    status_code=status,\n                    size_bytes=len(data),\n                    elapsed=elapsed,\n                    attempts=attempt,\n                )\n            except asyncio.TimeoutError:\n                error_msg = f\"Таймаут (спроба {attempt})\"\n            except Exception as e:\n                error_msg = f\"{type(e).__name__}: {e} (спроба {attempt})\"\n\n            # Якщо спроба невдала, робимо паузу з експоненціальним зростанням\n            if attempt \u003C max_retries:\n                await asyncio.sleep(retry_delay * attempt)\n\n    return ScrapeResult(\n        url=url,\n        success=False,\n        elapsed=time.perf_counter() - start,\n        attempts=max_retries,\n        error=error_msg,\n    )\n\nasync def scrape_all(\n    urls: list[str],\n    max_concurrent: int = 10,\n    max_retries: int = 3,\n    verbose: bool = True,\n) -> tuple[list[ScrapeResult], ScraperStats]:\n    \"\"\"Асинхронно завантажує список URL-адрес з виводом статистики.\"\"\"\n    semaphore = asyncio.Semaphore(max_concurrent)\n    stats = ScraperStats(total=len(urls))\n\n    with concurrent.futures.ThreadPoolExecutor(max_workers=max_concurrent) as executor:\n        tasks = [\n            fetch_url(url, semaphore, executor, max_retries)\n            for url in urls\n        ]\n\n        results: list[ScrapeResult] = []\n        t_start = time.perf_counter()\n\n        # ✅ Виправлено: обхід асинхронних результатів по мірі готовності (синхронний for)\n        for coro in asyncio.as_completed(tasks):\n            result = await coro\n            results.append(result)\n\n            if result.success:\n                stats.successful += 1\n                stats.total_bytes += result.size_bytes\n                if verbose:\n                    print(\n                        f\"  ✓ [{result.attempts} спр.] \"\n                        f\"{result.url[-45:]:\u003C45} \"\n                        f\"{result.size_bytes:>7,}b  {result.elapsed:.2f}s\"\n                    )\n            else:\n                stats.failed += 1\n                stats.errors[result.error] += 1\n                if verbose:\n                    print(f\"  ✗ {result.url[-45:]}: {result.error}\")\n\n        stats.total_time = time.perf_counter() - t_start\n\n    if verbose:\n        print(f\"\\n{'─' * 60}\")\n        print(f\"Всього URL:   {stats.total}\")\n        print(f\"Успішно:      {stats.successful}\")\n        print(f\"Помилок:      {stats.failed}\")\n        print(f\"Отримано:     {stats.total_bytes:,} байт\")\n        print(f\"Час:          {stats.total_time:.2f}s\")\n        if stats.total_time > 0:\n            avg_seq = sum(r.elapsed for r in results if r.success)\n            print(f\"Прискорення:  {avg_seq \u002F stats.total_time:.1f}x\")\n\n    return results, stats\n\nif __name__ == \"__main__\":\n    test_urls = [\n        f\"https:\u002F\u002Fhttpbin.org\u002Fdelay\u002F0.3?id={i}\" for i in range(20)\n    ]\n\n    print(f\"Скрапимо {len(test_urls)} URL (по ~0.3s кожен)\\n\")\n    results, stats = asyncio.run(scrape_all(test_urls, max_concurrent=8))\n",[3438,12305,12306,12311,12325,12329,12335,12341,12347,12359,12371,12377,12381,12386,12396,12404,12412,12423,12434,12446,12457,12469,12473,12477,12486,12497,12508,12519,12530,12541,12570,12574,12599,12604,12622,12629,12633,12645,12656,12664,12672,12687,12702,12707,12712,12716,12721,12725,12746,12758,12764,12769,12782,12791,12796,12801,12807,12816,12825,12837,12846,12859,12868,12877,12883,12890,12909,12922,12962,12967,12973,12982,12991,12996,13003,13011,13023,13032,13041,13050,13055,13060,13072,13086,13102,13117,13133,13139,13145,13151,13166,13171,13188,13193,13199,13210,13215,13220,13226,13232,13237,13243,13255,13265,13271,13276,13284,13292,13298,13307,13315,13334,13357,13384,13389,13397,13405,13413,13420,13454,13459,13465,13470,13477,13507,13530,13553,13576,13599,13622,13634,13662,13686,13691,13699,13704,13720,13726,13757,13762,13767,13797],{"__ignoreMap":3569},[3573,12307,12308],{"class":3575,"line":3576},[3573,12309,12310],{"class":3579},"# async_scraper.py\n",[3573,12312,12313,12316,12319,12322],{"class":3575,"line":3583},[3573,12314,12315],{"class":3586},"from",[3573,12317,12318],{"class":3615}," __future__",[3573,12320,12321],{"class":3586}," import",[3573,12323,12324],{"class":3590}," annotations\n",[3573,12326,12327],{"class":3575,"line":3594},[3573,12328,3598],{"emptyLinePlaceholder":3597},[3573,12330,12331,12333],{"class":3575,"line":3601},[3573,12332,3587],{"class":3586},[3573,12334,3591],{"class":3590},[3573,12336,12337,12339],{"class":3575,"line":3635},[3573,12338,3587],{"class":3586},[3573,12340,4718],{"class":3590},[3573,12342,12343,12345],{"class":3575,"line":3642},[3573,12344,3587],{"class":3586},[3573,12346,11052],{"class":3590},[3573,12348,12349,12351,12354,12356],{"class":3575,"line":3671},[3573,12350,12315],{"class":3586},[3573,12352,12353],{"class":3590}," dataclasses ",[3573,12355,3587],{"class":3586},[3573,12357,12358],{"class":3590}," dataclass, field\n",[3573,12360,12361,12363,12366,12368],{"class":3575,"line":3676},[3573,12362,12315],{"class":3586},[3573,12364,12365],{"class":3590}," collections ",[3573,12367,3587],{"class":3586},[3573,12369,12370],{"class":3590}," defaultdict\n",[3573,12372,12373,12375],{"class":3575,"line":3695},[3573,12374,3587],{"class":3586},[3573,12376,11045],{"class":3590},[3573,12378,12379],{"class":3575,"line":3701},[3573,12380,3598],{"emptyLinePlaceholder":3597},[3573,12382,12383],{"class":3575,"line":3721},[3573,12384,12385],{"class":3608},"@dataclass\n",[3573,12387,12388,12391,12394],{"class":3575,"line":3727},[3573,12389,12390],{"class":3604},"class",[3573,12392,12393],{"class":3622}," ScrapeResult",[3573,12395,3632],{"class":3590},[3573,12397,12398,12401],{"class":3575,"line":3816},[3573,12399,12400],{"class":3590},"    url: ",[3573,12402,12403],{"class":3622},"str\n",[3573,12405,12406,12409],{"class":3575,"line":3822},[3573,12407,12408],{"class":3590},"    success: ",[3573,12410,12411],{"class":3622},"bool\n",[3573,12413,12414,12417,12419,12421],{"class":3575,"line":3827},[3573,12415,12416],{"class":3590},"    status_code: ",[3573,12418,5645],{"class":3622},[3573,12420,10667],{"class":3590},[3573,12422,8749],{"class":4049},[3573,12424,12425,12428,12430,12432],{"class":3575,"line":3833},[3573,12426,12427],{"class":3590},"    size_bytes: ",[3573,12429,5645],{"class":3622},[3573,12431,10667],{"class":3590},[3573,12433,8749],{"class":4049},[3573,12435,12436,12439,12441,12443],{"class":3575,"line":3839},[3573,12437,12438],{"class":3590},"    elapsed: ",[3573,12440,6608],{"class":3622},[3573,12442,10667],{"class":3590},[3573,12444,12445],{"class":4049},"0.0\n",[3573,12447,12448,12451,12453,12455],{"class":3575,"line":3845},[3573,12449,12450],{"class":3590},"    attempts: ",[3573,12452,5645],{"class":3622},[3573,12454,10667],{"class":3590},[3573,12456,8749],{"class":4049},[3573,12458,12459,12462,12464,12466],{"class":3575,"line":3851},[3573,12460,12461],{"class":3590},"    error: ",[3573,12463,4736],{"class":3622},[3573,12465,10667],{"class":3590},[3573,12467,12468],{"class":3638},"\"\"\n",[3573,12470,12471],{"class":3575,"line":3856},[3573,12472,3598],{"emptyLinePlaceholder":3597},[3573,12474,12475],{"class":3575,"line":3862},[3573,12476,12385],{"class":3608},[3573,12478,12479,12481,12484],{"class":3575,"line":3868},[3573,12480,12390],{"class":3604},[3573,12482,12483],{"class":3622}," ScraperStats",[3573,12485,3632],{"class":3590},[3573,12487,12488,12491,12493,12495],{"class":3575,"line":3874},[3573,12489,12490],{"class":3590},"    total: ",[3573,12492,5645],{"class":3622},[3573,12494,10667],{"class":3590},[3573,12496,8749],{"class":4049},[3573,12498,12499,12502,12504,12506],{"class":3575,"line":3880},[3573,12500,12501],{"class":3590},"    successful: ",[3573,12503,5645],{"class":3622},[3573,12505,10667],{"class":3590},[3573,12507,8749],{"class":4049},[3573,12509,12510,12513,12515,12517],{"class":3575,"line":3886},[3573,12511,12512],{"class":3590},"    failed: ",[3573,12514,5645],{"class":3622},[3573,12516,10667],{"class":3590},[3573,12518,8749],{"class":4049},[3573,12520,12521,12524,12526,12528],{"class":3575,"line":3891},[3573,12522,12523],{"class":3590},"    total_bytes: ",[3573,12525,5645],{"class":3622},[3573,12527,10667],{"class":3590},[3573,12529,8749],{"class":4049},[3573,12531,12532,12535,12537,12539],{"class":3575,"line":3897},[3573,12533,12534],{"class":3590},"    total_time: ",[3573,12536,6608],{"class":3622},[3573,12538,10667],{"class":3590},[3573,12540,12445],{"class":4049},[3573,12542,12543,12546,12548,12550,12552,12555,12558,12560,12563,12566,12568],{"class":3575,"line":3902},[3573,12544,12545],{"class":3590},"    errors: dict[",[3573,12547,4736],{"class":3622},[3573,12549,4890],{"class":3590},[3573,12551,5645],{"class":3622},[3573,12553,12554],{"class":3590},"] = field(",[3573,12556,12557],{"class":3615},"default_factory",[3573,12559,6476],{"class":3590},[3573,12561,12562],{"class":3604},"lambda",[3573,12564,12565],{"class":3590},": defaultdict(",[3573,12567,5645],{"class":3622},[3573,12569,5333],{"class":3590},[3573,12571,12572],{"class":3575,"line":3908},[3573,12573,3598],{"emptyLinePlaceholder":3597},[3573,12575,12576,12578,12581,12583,12585,12587,12589,12591,12593,12595,12597],{"class":3575,"line":3913},[3573,12577,3605],{"class":3604},[3573,12579,12580],{"class":3608}," _sync_fetch",[3573,12582,3612],{"class":3590},[3573,12584,5710],{"class":3615},[3573,12586,3619],{"class":3590},[3573,12588,4736],{"class":3622},[3573,12590,7023],{"class":3590},[3573,12592,5645],{"class":3622},[3573,12594,4890],{"class":3590},[3573,12596,3623],{"class":3622},[3573,12598,7032],{"class":3590},[3573,12600,12601],{"class":3575,"line":3919},[3573,12602,12603],{"class":3638},"    \"\"\"Синхронний мережевий запит для виконання у пулі потоків.\"\"\"\n",[3573,12605,12606,12608,12610,12612,12614,12616,12618,12620],{"class":3575,"line":3925},[3573,12607,11087],{"class":3586},[3573,12609,11090],{"class":3590},[3573,12611,7504],{"class":3615},[3573,12613,6476],{"class":3590},[3573,12615,8217],{"class":4049},[3573,12617,11099],{"class":3590},[3573,12619,8492],{"class":3586},[3573,12621,11104],{"class":3590},[3573,12623,12624,12626],{"class":3575,"line":4576},[3573,12625,7265],{"class":3586},[3573,12627,12628],{"class":3590}," r.status, r.read()\n",[3573,12630,12631],{"class":3575,"line":4582},[3573,12632,3598],{"emptyLinePlaceholder":3597},[3573,12634,12635,12637,12639,12642],{"class":3575,"line":4588},[3573,12636,4005],{"class":3604},[3573,12638,4008],{"class":3604},[3573,12640,12641],{"class":3608}," fetch_url",[3573,12643,12644],{"class":3590},"(\n",[3573,12646,12647,12650,12652,12654],{"class":3575,"line":4593},[3573,12648,12649],{"class":3615},"    url",[3573,12651,3619],{"class":3590},[3573,12653,4736],{"class":3622},[3573,12655,7082],{"class":3590},[3573,12657,12658,12661],{"class":3575,"line":4599},[3573,12659,12660],{"class":3615},"    semaphore",[3573,12662,12663],{"class":3590},": asyncio.Semaphore,\n",[3573,12665,12666,12669],{"class":3575,"line":4604},[3573,12667,12668],{"class":3615},"    executor",[3573,12670,12671],{"class":3590},": concurrent.futures.ThreadPoolExecutor,\n",[3573,12673,12674,12677,12679,12681,12683,12685],{"class":3575,"line":4609},[3573,12675,12676],{"class":3615},"    max_retries",[3573,12678,3619],{"class":3590},[3573,12680,5645],{"class":3622},[3573,12682,10667],{"class":3590},[3573,12684,4105],{"class":4049},[3573,12686,7082],{"class":3590},[3573,12688,12689,12692,12694,12696,12698,12700],{"class":3575,"line":4614},[3573,12690,12691],{"class":3615},"    retry_delay",[3573,12693,3619],{"class":3590},[3573,12695,6608],{"class":3622},[3573,12697,10667],{"class":3590},[3573,12699,4795],{"class":4049},[3573,12701,7082],{"class":3590},[3573,12703,12704],{"class":3575,"line":4620},[3573,12705,12706],{"class":3590},") -> ScrapeResult:\n",[3573,12708,12709],{"class":3575,"line":4626},[3573,12710,12711],{"class":3638},"    \"\"\"Завантажує URL з обмеженням конкурентності, таймаутом і повторними спробами.\"\"\"\n",[3573,12713,12714],{"class":3575,"line":4631},[3573,12715,6102],{"class":3590},[3573,12717,12718],{"class":3575,"line":4636},[3573,12719,12720],{"class":3590},"    start = time.perf_counter()\n",[3573,12722,12723],{"class":3575,"line":4642},[3573,12724,3598],{"emptyLinePlaceholder":3597},[3573,12726,12727,12729,12731,12733,12735,12737,12739,12742,12744],{"class":3575,"line":4647},[3573,12728,4091],{"class":3586},[3573,12730,10682],{"class":3590},[3573,12732,4097],{"class":3586},[3573,12734,4100],{"class":3608},[3573,12736,3612],{"class":3590},[3573,12738,4050],{"class":4049},[3573,12740,12741],{"class":3590},", max_retries + ",[3573,12743,4050],{"class":4049},[3573,12745,4108],{"class":3590},[3573,12747,12748,12750,12752,12755],{"class":3575,"line":4653},[3573,12749,8483],{"class":3586},[3573,12751,8486],{"class":3586},[3573,12753,12754],{"class":3590}," semaphore:    ",[3573,12756,12757],{"class":3579},"# Обмежуємо кількість одночасних запитів\n",[3573,12759,12760,12762],{"class":3575,"line":4658},[3573,12761,10702],{"class":3586},[3573,12763,3632],{"class":3590},[3573,12765,12766],{"class":3575,"line":4664},[3573,12767,12768],{"class":3579},"                # Встановлюємо жорсткий таймаут на виконання всього запиту\n",[3573,12770,12771,12773,12775,12777,12780],{"class":3575,"line":4669},[3573,12772,10714],{"class":3586},[3573,12774,8486],{"class":3586},[3573,12776,10543],{"class":3590},[3573,12778,12779],{"class":4049},"8.0",[3573,12781,4108],{"class":3590},[3573,12783,12784,12787,12789],{"class":3575,"line":11479},[3573,12785,12786],{"class":3590},"                    status, data = ",[3573,12788,3488],{"class":3586},[3573,12790,11241],{"class":3590},[3573,12792,12793],{"class":3575,"line":11501},[3573,12794,12795],{"class":3590},"                        executor, _sync_fetch, url\n",[3573,12797,12798],{"class":3575,"line":11506},[3573,12799,12800],{"class":3590},"                    )\n",[3573,12802,12804],{"class":3575,"line":12803},54,[3573,12805,12806],{"class":3590},"                elapsed = time.perf_counter() - start\n",[3573,12808,12810,12813],{"class":3575,"line":12809},55,[3573,12811,12812],{"class":3586},"                return",[3573,12814,12815],{"class":3590}," ScrapeResult(\n",[3573,12817,12819,12822],{"class":3575,"line":12818},56,[3573,12820,12821],{"class":3615},"                    url",[3573,12823,12824],{"class":3590},"=url,\n",[3573,12826,12828,12831,12833,12835],{"class":3575,"line":12827},57,[3573,12829,12830],{"class":3615},"                    success",[3573,12832,6476],{"class":3590},[3573,12834,5414],{"class":3604},[3573,12836,7082],{"class":3590},[3573,12838,12840,12843],{"class":3575,"line":12839},58,[3573,12841,12842],{"class":3615},"                    status_code",[3573,12844,12845],{"class":3590},"=status,\n",[3573,12847,12849,12852,12854,12856],{"class":3575,"line":12848},59,[3573,12850,12851],{"class":3615},"                    size_bytes",[3573,12853,6476],{"class":3590},[3573,12855,7816],{"class":3608},[3573,12857,12858],{"class":3590},"(data),\n",[3573,12860,12862,12865],{"class":3575,"line":12861},60,[3573,12863,12864],{"class":3615},"                    elapsed",[3573,12866,12867],{"class":3590},"=elapsed,\n",[3573,12869,12871,12874],{"class":3575,"line":12870},61,[3573,12872,12873],{"class":3615},"                    attempts",[3573,12875,12876],{"class":3590},"=attempt,\n",[3573,12878,12880],{"class":3575,"line":12879},62,[3573,12881,12882],{"class":3590},"                )\n",[3573,12884,12886,12888],{"class":3575,"line":12885},63,[3573,12887,10786],{"class":3586},[3573,12889,10568],{"class":3590},[3573,12891,12893,12896,12898,12901,12903,12905,12907],{"class":3575,"line":12892},64,[3573,12894,12895],{"class":3590},"                error_msg = ",[3573,12897,3650],{"class":3604},[3573,12899,12900],{"class":3638},"\"Таймаут (спроба ",[3573,12902,3656],{"class":3604},[3573,12904,10776],{"class":3590},[3573,12906,3662],{"class":3604},[3573,12908,10781],{"class":3638},[3573,12910,12912,12914,12917,12919],{"class":3575,"line":12911},65,[3573,12913,10786],{"class":3586},[3573,12915,12916],{"class":3622}," Exception",[3573,12918,8599],{"class":3586},[3573,12920,12921],{"class":3590}," e:\n",[3573,12923,12925,12927,12929,12931,12933,12935,12938,12941,12943,12945,12947,12950,12952,12954,12956,12958,12960],{"class":3575,"line":12924},66,[3573,12926,12895],{"class":3590},[3573,12928,3650],{"class":3604},[3573,12930,3665],{"class":3638},[3573,12932,3656],{"class":3604},[3573,12934,5263],{"class":3622},[3573,12936,12937],{"class":3590},"(e).",[3573,12939,12940],{"class":3615},"__name__",[3573,12942,3662],{"class":3604},[3573,12944,3619],{"class":3638},[3573,12946,3656],{"class":3604},[3573,12948,12949],{"class":3590},"e",[3573,12951,3662],{"class":3604},[3573,12953,10771],{"class":3638},[3573,12955,3656],{"class":3604},[3573,12957,10776],{"class":3590},[3573,12959,3662],{"class":3604},[3573,12961,10781],{"class":3638},[3573,12963,12965],{"class":3575,"line":12964},67,[3573,12966,3598],{"emptyLinePlaceholder":3597},[3573,12968,12970],{"class":3575,"line":12969},68,[3573,12971,12972],{"class":3579},"            # Якщо спроба невдала, робимо паузу з експоненціальним зростанням\n",[3573,12974,12976,12979],{"class":3575,"line":12975},69,[3573,12977,12978],{"class":3586},"            if",[3573,12980,12981],{"class":3590}," attempt \u003C max_retries:\n",[3573,12983,12985,12988],{"class":3575,"line":12984},70,[3573,12986,12987],{"class":3586},"                await",[3573,12989,12990],{"class":3590}," asyncio.sleep(retry_delay * attempt)\n",[3573,12992,12994],{"class":3575,"line":12993},71,[3573,12995,3598],{"emptyLinePlaceholder":3597},[3573,12997,12999,13001],{"class":3575,"line":12998},72,[3573,13000,4759],{"class":3586},[3573,13002,12815],{"class":3590},[3573,13004,13006,13009],{"class":3575,"line":13005},73,[3573,13007,13008],{"class":3615},"        url",[3573,13010,12824],{"class":3590},[3573,13012,13014,13017,13019,13021],{"class":3575,"line":13013},74,[3573,13015,13016],{"class":3615},"        success",[3573,13018,6476],{"class":3590},[3573,13020,6952],{"class":3604},[3573,13022,7082],{"class":3590},[3573,13024,13026,13029],{"class":3575,"line":13025},75,[3573,13027,13028],{"class":3615},"        elapsed",[3573,13030,13031],{"class":3590},"=time.perf_counter() - start,\n",[3573,13033,13035,13038],{"class":3575,"line":13034},76,[3573,13036,13037],{"class":3615},"        attempts",[3573,13039,13040],{"class":3590},"=max_retries,\n",[3573,13042,13044,13047],{"class":3575,"line":13043},77,[3573,13045,13046],{"class":3615},"        error",[3573,13048,13049],{"class":3590},"=error_msg,\n",[3573,13051,13053],{"class":3575,"line":13052},78,[3573,13054,7147],{"class":3590},[3573,13056,13058],{"class":3575,"line":13057},79,[3573,13059,3598],{"emptyLinePlaceholder":3597},[3573,13061,13063,13065,13067,13070],{"class":3575,"line":13062},80,[3573,13064,4005],{"class":3604},[3573,13066,4008],{"class":3604},[3573,13068,13069],{"class":3608}," scrape_all",[3573,13071,12644],{"class":3590},[3573,13073,13075,13078,13081,13083],{"class":3575,"line":13074},81,[3573,13076,13077],{"class":3615},"    urls",[3573,13079,13080],{"class":3590},": list[",[3573,13082,4736],{"class":3622},[3573,13084,13085],{"class":3590},"],\n",[3573,13087,13089,13092,13094,13096,13098,13100],{"class":3575,"line":13088},82,[3573,13090,13091],{"class":3615},"    max_concurrent",[3573,13093,3619],{"class":3590},[3573,13095,5645],{"class":3622},[3573,13097,10667],{"class":3590},[3573,13099,8217],{"class":4049},[3573,13101,7082],{"class":3590},[3573,13103,13105,13107,13109,13111,13113,13115],{"class":3575,"line":13104},83,[3573,13106,12676],{"class":3615},[3573,13108,3619],{"class":3590},[3573,13110,5645],{"class":3622},[3573,13112,10667],{"class":3590},[3573,13114,4105],{"class":4049},[3573,13116,7082],{"class":3590},[3573,13118,13120,13123,13125,13127,13129,13131],{"class":3575,"line":13119},84,[3573,13121,13122],{"class":3615},"    verbose",[3573,13124,3619],{"class":3590},[3573,13126,6964],{"class":3622},[3573,13128,10667],{"class":3590},[3573,13130,5414],{"class":3604},[3573,13132,7082],{"class":3590},[3573,13134,13136],{"class":3575,"line":13135},85,[3573,13137,13138],{"class":3590},") -> tuple[list[ScrapeResult], ScraperStats]:\n",[3573,13140,13142],{"class":3575,"line":13141},86,[3573,13143,13144],{"class":3638},"    \"\"\"Асинхронно завантажує список URL-адрес з виводом статистики.\"\"\"\n",[3573,13146,13148],{"class":3575,"line":13147},87,[3573,13149,13150],{"class":3590},"    semaphore = asyncio.Semaphore(max_concurrent)\n",[3573,13152,13154,13157,13159,13161,13163],{"class":3575,"line":13153},88,[3573,13155,13156],{"class":3590},"    stats = ScraperStats(",[3573,13158,10222],{"class":3615},[3573,13160,6476],{"class":3590},[3573,13162,7816],{"class":3608},[3573,13164,13165],{"class":3590},"(urls))\n",[3573,13167,13169],{"class":3575,"line":13168},89,[3573,13170,3598],{"emptyLinePlaceholder":3597},[3573,13172,13174,13176,13178,13180,13183,13185],{"class":3575,"line":13173},90,[3573,13175,11087],{"class":3586},[3573,13177,11213],{"class":3590},[3573,13179,11216],{"class":3615},[3573,13181,13182],{"class":3590},"=max_concurrent) ",[3573,13184,8492],{"class":3586},[3573,13186,13187],{"class":3590}," executor:\n",[3573,13189,13191],{"class":3575,"line":13190},91,[3573,13192,11314],{"class":3590},[3573,13194,13196],{"class":3575,"line":13195},92,[3573,13197,13198],{"class":3590},"            fetch_url(url, semaphore, executor, max_retries)\n",[3573,13200,13202,13204,13206,13208],{"class":3575,"line":13201},93,[3573,13203,11324],{"class":3586},[3573,13205,11327],{"class":3590},[3573,13207,4097],{"class":3586},[3573,13209,11332],{"class":3590},[3573,13211,13213],{"class":3575,"line":13212},94,[3573,13214,11337],{"class":3590},[3573,13216,13218],{"class":3575,"line":13217},95,[3573,13219,3598],{"emptyLinePlaceholder":3597},[3573,13221,13223],{"class":3575,"line":13222},96,[3573,13224,13225],{"class":3590},"        results: list[ScrapeResult] = []\n",[3573,13227,13229],{"class":3575,"line":13228},97,[3573,13230,13231],{"class":3590},"        t_start = time.perf_counter()\n",[3573,13233,13235],{"class":3575,"line":13234},98,[3573,13236,3598],{"emptyLinePlaceholder":3597},[3573,13238,13240],{"class":3575,"line":13239},99,[3573,13241,13242],{"class":3579},"        # ✅ Виправлено: обхід асинхронних результатів по мірі готовності (синхронний for)\n",[3573,13244,13246,13248,13251,13253],{"class":3575,"line":13245},100,[3573,13247,8024],{"class":3586},[3573,13249,13250],{"class":3590}," coro ",[3573,13252,4097],{"class":3586},[3573,13254,8252],{"class":3590},[3573,13256,13258,13260,13262],{"class":3575,"line":13257},101,[3573,13259,10556],{"class":3590},[3573,13261,3488],{"class":3586},[3573,13263,13264],{"class":3590}," coro\n",[3573,13266,13268],{"class":3575,"line":13267},102,[3573,13269,13270],{"class":3590},"            results.append(result)\n",[3573,13272,13274],{"class":3575,"line":13273},103,[3573,13275,3598],{"emptyLinePlaceholder":3597},[3573,13277,13279,13281],{"class":3575,"line":13278},104,[3573,13280,12978],{"class":3586},[3573,13282,13283],{"class":3590}," result.success:\n",[3573,13285,13287,13290],{"class":3575,"line":13286},105,[3573,13288,13289],{"class":3590},"                stats.successful += ",[3573,13291,5660],{"class":4049},[3573,13293,13295],{"class":3575,"line":13294},106,[3573,13296,13297],{"class":3590},"                stats.total_bytes += result.size_bytes\n",[3573,13299,13301,13304],{"class":3575,"line":13300},107,[3573,13302,13303],{"class":3586},"                if",[3573,13305,13306],{"class":3590}," verbose:\n",[3573,13308,13310,13313],{"class":3575,"line":13309},108,[3573,13311,13312],{"class":3608},"                    print",[3573,13314,12644],{"class":3590},[3573,13316,13318,13321,13324,13326,13329,13331],{"class":3575,"line":13317},109,[3573,13319,13320],{"class":3604},"                        f",[3573,13322,13323],{"class":3638},"\"  ✓ [",[3573,13325,3656],{"class":3604},[3573,13327,13328],{"class":3590},"result.attempts",[3573,13330,3662],{"class":3604},[3573,13332,13333],{"class":3638}," спр.] \"\n",[3573,13335,13337,13339,13341,13343,13346,13349,13351,13354],{"class":3575,"line":13336},110,[3573,13338,13320],{"class":3604},[3573,13340,3665],{"class":3638},[3573,13342,3656],{"class":3604},[3573,13344,13345],{"class":3590},"result.url[-",[3573,13347,13348],{"class":4049},"45",[3573,13350,9193],{"class":3590},[3573,13352,13353],{"class":3604},":\u003C45}",[3573,13355,13356],{"class":3638}," \"\n",[3573,13358,13360,13362,13364,13366,13369,13372,13375,13377,13380,13382],{"class":3575,"line":13359},111,[3573,13361,13320],{"class":3604},[3573,13363,3665],{"class":3638},[3573,13365,3656],{"class":3604},[3573,13367,13368],{"class":3590},"result.size_bytes",[3573,13370,13371],{"class":3604},":>7,}",[3573,13373,13374],{"class":3638},"b  ",[3573,13376,3656],{"class":3604},[3573,13378,13379],{"class":3590},"result.elapsed",[3573,13381,6863],{"class":3604},[3573,13383,6698],{"class":3638},[3573,13385,13387],{"class":3575,"line":13386},112,[3573,13388,12800],{"class":3590},[3573,13390,13392,13395],{"class":3575,"line":13391},113,[3573,13393,13394],{"class":3586},"            else",[3573,13396,3632],{"class":3590},[3573,13398,13400,13403],{"class":3575,"line":13399},114,[3573,13401,13402],{"class":3590},"                stats.failed += ",[3573,13404,5660],{"class":4049},[3573,13406,13408,13411],{"class":3575,"line":13407},115,[3573,13409,13410],{"class":3590},"                stats.errors[result.error] += ",[3573,13412,5660],{"class":4049},[3573,13414,13416,13418],{"class":3575,"line":13415},116,[3573,13417,13303],{"class":3586},[3573,13419,13306],{"class":3590},[3573,13421,13423,13425,13427,13429,13431,13433,13435,13437,13439,13441,13443,13445,13448,13450,13452],{"class":3575,"line":13422},117,[3573,13424,13312],{"class":3608},[3573,13426,3612],{"class":3590},[3573,13428,3650],{"class":3604},[3573,13430,7388],{"class":3638},[3573,13432,3656],{"class":3604},[3573,13434,13345],{"class":3590},[3573,13436,13348],{"class":4049},[3573,13438,9193],{"class":3590},[3573,13440,3662],{"class":3604},[3573,13442,3619],{"class":3638},[3573,13444,3656],{"class":3604},[3573,13446,13447],{"class":3590},"result.error",[3573,13449,3662],{"class":3604},[3573,13451,3665],{"class":3638},[3573,13453,3668],{"class":3590},[3573,13455,13457],{"class":3575,"line":13456},118,[3573,13458,3598],{"emptyLinePlaceholder":3597},[3573,13460,13462],{"class":3575,"line":13461},119,[3573,13463,13464],{"class":3590},"        stats.total_time = time.perf_counter() - t_start\n",[3573,13466,13468],{"class":3575,"line":13467},120,[3573,13469,3598],{"emptyLinePlaceholder":3597},[3573,13471,13473,13475],{"class":3575,"line":13472},121,[3573,13474,7991],{"class":3586},[3573,13476,13306],{"class":3590},[3573,13478,13480,13482,13484,13486,13488,13490,13492,13495,13498,13501,13503,13505],{"class":3575,"line":13479},122,[3573,13481,4113],{"class":3608},[3573,13483,3612],{"class":3590},[3573,13485,3650],{"class":3604},[3573,13487,3665],{"class":3638},[3573,13489,3714],{"class":3713},[3573,13491,3656],{"class":3604},[3573,13493,13494],{"class":3638},"'─'",[3573,13496,13497],{"class":3590}," * ",[3573,13499,13500],{"class":4049},"60",[3573,13502,3662],{"class":3604},[3573,13504,3665],{"class":3638},[3573,13506,3668],{"class":3590},[3573,13508,13510,13512,13514,13516,13519,13521,13524,13526,13528],{"class":3575,"line":13509},123,[3573,13511,4113],{"class":3608},[3573,13513,3612],{"class":3590},[3573,13515,3650],{"class":3604},[3573,13517,13518],{"class":3638},"\"Всього URL:   ",[3573,13520,3656],{"class":3604},[3573,13522,13523],{"class":3590},"stats.total",[3573,13525,3662],{"class":3604},[3573,13527,3665],{"class":3638},[3573,13529,3668],{"class":3590},[3573,13531,13533,13535,13537,13539,13542,13544,13547,13549,13551],{"class":3575,"line":13532},124,[3573,13534,4113],{"class":3608},[3573,13536,3612],{"class":3590},[3573,13538,3650],{"class":3604},[3573,13540,13541],{"class":3638},"\"Успішно:      ",[3573,13543,3656],{"class":3604},[3573,13545,13546],{"class":3590},"stats.successful",[3573,13548,3662],{"class":3604},[3573,13550,3665],{"class":3638},[3573,13552,3668],{"class":3590},[3573,13554,13556,13558,13560,13562,13565,13567,13570,13572,13574],{"class":3575,"line":13555},125,[3573,13557,4113],{"class":3608},[3573,13559,3612],{"class":3590},[3573,13561,3650],{"class":3604},[3573,13563,13564],{"class":3638},"\"Помилок:      ",[3573,13566,3656],{"class":3604},[3573,13568,13569],{"class":3590},"stats.failed",[3573,13571,3662],{"class":3604},[3573,13573,3665],{"class":3638},[3573,13575,3668],{"class":3590},[3573,13577,13579,13581,13583,13585,13588,13590,13593,13595,13597],{"class":3575,"line":13578},126,[3573,13580,4113],{"class":3608},[3573,13582,3612],{"class":3590},[3573,13584,3650],{"class":3604},[3573,13586,13587],{"class":3638},"\"Отримано:     ",[3573,13589,3656],{"class":3604},[3573,13591,13592],{"class":3590},"stats.total_bytes",[3573,13594,11444],{"class":3604},[3573,13596,11284],{"class":3638},[3573,13598,3668],{"class":3590},[3573,13600,13602,13604,13606,13608,13611,13613,13616,13618,13620],{"class":3575,"line":13601},127,[3573,13603,4113],{"class":3608},[3573,13605,3612],{"class":3590},[3573,13607,3650],{"class":3604},[3573,13609,13610],{"class":3638},"\"Час:          ",[3573,13612,3656],{"class":3604},[3573,13614,13615],{"class":3590},"stats.total_time",[3573,13617,6863],{"class":3604},[3573,13619,4923],{"class":3638},[3573,13621,3668],{"class":3590},[3573,13623,13625,13627,13630,13632],{"class":3575,"line":13624},128,[3573,13626,7216],{"class":3586},[3573,13628,13629],{"class":3590}," stats.total_time > ",[3573,13631,5655],{"class":4049},[3573,13633,3632],{"class":3590},[3573,13635,13637,13640,13643,13646,13648,13651,13653,13656,13659],{"class":3575,"line":13636},129,[3573,13638,13639],{"class":3590},"            avg_seq = ",[3573,13641,13642],{"class":3608},"sum",[3573,13644,13645],{"class":3590},"(r.elapsed ",[3573,13647,5580],{"class":3586},[3573,13649,13650],{"class":3590}," r ",[3573,13652,4097],{"class":3586},[3573,13654,13655],{"class":3590}," results ",[3573,13657,13658],{"class":3586},"if",[3573,13660,13661],{"class":3590}," r.success)\n",[3573,13663,13665,13667,13669,13671,13674,13676,13679,13681,13684],{"class":3575,"line":13664},130,[3573,13666,7381],{"class":3608},[3573,13668,3612],{"class":3590},[3573,13670,3650],{"class":3604},[3573,13672,13673],{"class":3638},"\"Прискорення:  ",[3573,13675,3656],{"class":3604},[3573,13677,13678],{"class":3590},"avg_seq \u002F stats.total_time",[3573,13680,9439],{"class":3604},[3573,13682,13683],{"class":3638},"x\"",[3573,13685,3668],{"class":3590},[3573,13687,13689],{"class":3575,"line":13688},131,[3573,13690,3598],{"emptyLinePlaceholder":3597},[3573,13692,13694,13696],{"class":3575,"line":13693},132,[3573,13695,4759],{"class":3586},[3573,13697,13698],{"class":3590}," results, stats\n",[3573,13700,13702],{"class":3575,"line":13701},133,[3573,13703,3598],{"emptyLinePlaceholder":3597},[3573,13705,13707,13709,13712,13715,13718],{"class":3575,"line":13706},134,[3573,13708,13658],{"class":3586},[3573,13710,13711],{"class":3615}," __name__",[3573,13713,13714],{"class":3590}," == ",[3573,13716,13717],{"class":3638},"\"__main__\"",[3573,13719,3632],{"class":3590},[3573,13721,13723],{"class":3575,"line":13722},135,[3573,13724,13725],{"class":3590},"    test_urls = [\n",[3573,13727,13729,13732,13735,13737,13739,13741,13743,13745,13747,13749,13751,13753,13755],{"class":3575,"line":13728},136,[3573,13730,13731],{"class":3604},"        f",[3573,13733,13734],{"class":3638},"\"https:\u002F\u002Fhttpbin.org\u002Fdelay\u002F0.3?id=",[3573,13736,3656],{"class":3604},[3573,13738,4125],{"class":3590},[3573,13740,3662],{"class":3604},[3573,13742,3665],{"class":3638},[3573,13744,5839],{"class":3586},[3573,13746,4094],{"class":3590},[3573,13748,4097],{"class":3586},[3573,13750,4100],{"class":3608},[3573,13752,3612],{"class":3590},[3573,13754,9190],{"class":4049},[3573,13756,3668],{"class":3590},[3573,13758,13760],{"class":3575,"line":13759},137,[3573,13761,7108],{"class":3590},[3573,13763,13765],{"class":3575,"line":13764},138,[3573,13766,3598],{"emptyLinePlaceholder":3597},[3573,13768,13770,13772,13774,13776,13779,13781,13783,13786,13788,13791,13793,13795],{"class":3575,"line":13769},139,[3573,13771,3645],{"class":3608},[3573,13773,3612],{"class":3590},[3573,13775,3650],{"class":3604},[3573,13777,13778],{"class":3638},"\"Скрапимо ",[3573,13780,3656],{"class":3604},[3573,13782,7816],{"class":3608},[3573,13784,13785],{"class":3590},"(test_urls)",[3573,13787,3662],{"class":3604},[3573,13789,13790],{"class":3638}," URL (по ~0.3s кожен)",[3573,13792,3714],{"class":3713},[3573,13794,3665],{"class":3638},[3573,13796,3668],{"class":3590},[3573,13798,13800,13803,13806,13808,13810],{"class":3575,"line":13799},140,[3573,13801,13802],{"class":3590},"    results, stats = asyncio.run(scrape_all(test_urls, ",[3573,13804,13805],{"class":3615},"max_concurrent",[3573,13807,6476],{"class":3590},[3573,13809,10352],{"class":4049},[3573,13811,5333],{"class":3590},[4195,13813,13815,13823,13827,13830,13842,13853,13860,13864,13871,13878,13885,13894,13902],{"title":13814},"python async_scraper.py",[4199,13816,13818,4207,13821],{"className":13817},[3575],[3573,13819,4206],{"className":13820},[4205],[3398,13822,13814],{},[4199,13824,13826],{"className":13825},[3575],"Скрапимо 20 URL (по ~0.3s кожен)",[4199,13828],{"className":13829},[3575],[4199,13831,13833,13834,5048,13838],{"className":13832},[3575],"  ✓ [1 спр.] httpbin.org\u002Fdelay\u002F0.3?id=3          ",[3573,13835,13837],{"className":13836},[5406],"    220b",[3573,13839,13841],{"className":13840},[5069],"0.38s",[4199,13843,13845,13846,5048,13849],{"className":13844},[3575],"  ✓ [1 спр.] httpbin.org\u002Fdelay\u002F0.3?id=1          ",[3573,13847,13837],{"className":13848},[5406],[3573,13850,13852],{"className":13851},[5069],"0.41s",[4199,13854,5048,13856],{"className":13855},[3575],[3573,13857,13859],{"className":13858},[4205],"... (решта 18 результатів)",[4199,13861,13863],{"className":13862},[3575],"────────────────────────────────────────────────────────────",[4199,13865,13867,13868],{"className":13866},[3575],"Всього URL:   ",[3573,13869,9190],{"className":13870},[5406],[4199,13872,13874,13875],{"className":13873},[3575],"Успішно:      ",[3573,13876,9190],{"className":13877},[5069],[4199,13879,13881,13882],{"className":13880},[3575],"Помилок:      ",[3573,13883,5655],{"className":13884},[5046],[4199,13886,13888,13889,13893],{"className":13887},[3575],"Отримано:     ",[3573,13890,13892],{"className":13891},[5406],"4,400"," байт",[4199,13895,13897,13898],{"className":13896},[3575],"Час:          ",[3573,13899,13901],{"className":13900},[5069],"0.82s",[4199,13903,13905,13906],{"className":13904},[3575],"Прискорення:  ",[3573,13907,13909],{"className":13908},[5069],"9.1x",[3458,13911],{},[3389,13913,13915],{"id":13914},"підсумок-таблиця-api-та-ключові-принципи","Підсумок: таблиця API та ключові принципи",[3461,13917,13919],{"id":13918},"повне-api-asyncio","Повне API asyncio",[5456,13921,13922,13934],{},[5459,13923,13924],{},[5462,13925,13926,13929,13932],{},[5465,13927,13928],{"align":5467},"Функція \u002F Клас",[5465,13930,13931],{"align":5467},"Сигнатура \u002F Тип",[5465,13933,5542],{"align":5467},[5480,13935,13936,13952,13971,13987,14009,14025,14039,14056,14072,14088,14102,14118,14131,14147,14163,14183],{},[5462,13937,13938,13944,13949],{},[5485,13939,13940],{"align":5467},[3398,13941,13942],{},[3438,13943,6184],{},[5485,13945,13946],{"align":5467},[3438,13947,13948],{},"run(coro, *, debug=None)",[5485,13950,13951],{"align":5467},"Створює Event Loop, запускає корутину як точку входу та коректно завершує цикл.",[5462,13953,13954,13960,13965],{},[5485,13955,13956],{"align":5467},[3398,13957,13958],{},[3438,13959,5089],{},[5485,13961,13962],{"align":5467},[3438,13963,13964],{},"create_task(coro, *, name=None)",[5485,13966,13967,13968,13970],{"align":5467},"Обертає корутину в ",[3438,13969,6420],{}," та реєструє її у черзі виконання Event Loop.",[5462,13972,13973,13979,13984],{},[5485,13974,13975],{"align":5467},[3398,13976,13977],{},[3438,13978,4694],{},[5485,13980,13981],{"align":5467},[3438,13982,13983],{},"gather(*aws, return_exceptions=False)",[5485,13985,13986],{"align":5467},"Конкурентно запускає кілька задач і повертає список їхніх результатів.",[5462,13988,13989,13995,14000],{},[5485,13990,13991],{"align":5467},[3398,13992,13993],{},[3438,13994,7466],{},[5485,13996,13997],{"align":5467},[3438,13998,13999],{},"wait(aws, *, timeout=None, return_when=...)",[5485,14001,14002,14003,14005,14006,14008],{"align":5467},"Очікує завершення задач, повертаючи множини виконаних (",[3438,14004,7483],{},") та незавершених (",[3438,14007,7487],{},") задач.",[5462,14010,14011,14017,14022],{},[5485,14012,14013],{"align":5467},[3398,14014,14015],{},[3438,14016,8051],{},[5485,14018,14019],{"align":5467},[3438,14020,14021],{},"as_completed(aws, *, timeout=None)",[5485,14023,14024],{"align":5467},"Повертає ітератор, який видає результати задач по мірі їх завершення.",[5462,14026,14027,14033,14036],{},[5485,14028,14029],{"align":5467},[3398,14030,14031],{},[3438,14032,5093],{},[5485,14034,14035],{"align":5467},"Контекстний менеджер",[5485,14037,14038],{"align":5467},"Дозволяє керувати групою задач на основі принципів структурованої конкурентності (Python 3.11+).",[5462,14040,14041,14048,14053],{},[5485,14042,14043],{"align":5467},[3398,14044,14045],{},[3438,14046,14047],{},"asyncio.sleep()",[5485,14049,14050],{"align":5467},[3438,14051,14052],{},"sleep(delay, result=None)",[5485,14054,14055],{"align":5467},"Робить асинхронну паузу на вказаний час, не блокуючи Event Loop.",[5462,14057,14058,14064,14069],{},[5485,14059,14060],{"align":5467},[3398,14061,14062],{},[3438,14063,10394],{},[5485,14065,14066],{"align":5467},[3438,14067,14068],{},"timeout(delay)",[5485,14070,14071],{"align":5467},"Обмежує час виконання всього блоку коду (Python 3.11+).",[5462,14073,14074,14080,14085],{},[5485,14075,14076],{"align":5467},[3398,14077,14078],{},[3438,14079,10397],{},[5485,14081,14082],{"align":5467},[3438,14083,14084],{},"wait_for(aw, timeout)",[5485,14086,14087],{"align":5467},"Обгортає асинхронну задачу та обмежує час її очікування.",[5462,14089,14090,14096,14099],{},[5485,14091,14092],{"align":5467},[3398,14093,14094],{},[3438,14095,8672],{},[5485,14097,14098],{"align":5467},"Клас",[5485,14100,14101],{"align":5467},"Асинхронний мютекс для запобігання стану гонки та захисту критичних зон.",[5462,14103,14104,14110,14115],{},[5485,14105,14106],{"align":5467},[3398,14107,14108],{},[3438,14109,9000],{},[5485,14111,14112],{"align":5467},[3438,14113,14114],{},"Semaphore(value=1)",[5485,14116,14117],{"align":5467},"Асинхронний семафор для обмеження кількості конкурентних викликів.",[5462,14119,14120,14126,14128],{},[5485,14121,14122],{"align":5467},[3398,14123,14124],{},[3438,14125,9459],{},[5485,14127,14098],{"align":5467},[5485,14129,14130],{"align":5467},"Одноразовий сигнал сповіщення для синхронізації корутин.",[5462,14132,14133,14139,14144],{},[5485,14134,14135],{"align":5467},[3398,14136,14137],{},[3438,14138,9841],{},[5485,14140,14141],{"align":5467},[3438,14142,14143],{},"Queue(maxsize=0)",[5485,14145,14146],{"align":5467},"Асинхронна FIFO-черга для реалізації патерну Producer-Consumer.",[5462,14148,14149,14155,14160],{},[5485,14150,14151],{"align":5467},[3398,14152,14153],{},[3438,14154,10932],{},[5485,14156,14157],{"align":5467},[3438,14158,14159],{},"run_in_executor(executor, func, *args)",[5485,14161,14162],{"align":5467},"Запускає блокуючу синхронну функцію в окремому потоці або процесі.",[5462,14164,14165,14172,14177],{},[5485,14166,14167],{"align":5467},[3398,14168,14169],{},[3438,14170,14171],{},"asyncio.current_task()",[5485,14173,14174],{"align":5467},[3438,14175,14176],{},"current_task(loop=None)",[5485,14178,14179,14180,14182],{"align":5467},"Повертає об'єкт ",[3438,14181,6420],{},", який виконується в даний момент.",[5462,14184,14185,14192,14197],{},[5485,14186,14187],{"align":5467},[3398,14188,14189],{},[3438,14190,14191],{},"asyncio.all_tasks()",[5485,14193,14194],{"align":5467},[3438,14195,14196],{},"all_tasks(loop=None)",[5485,14198,14199],{"align":5467},"Повертає множину всіх незавершених задач для подієвого циклу.",[3461,14201,14203],{"id":14202},"порівняння-механізмів-конкурентного-групування","Порівняння механізмів конкурентного групування",[5456,14205,14206,14231],{},[5459,14207,14208],{},[5462,14209,14210,14212,14217,14222,14227],{},[5465,14211,5468],{"align":5467},[5465,14213,14214],{"align":5467},[3438,14215,14216],{},"asyncio.gather",[5465,14218,14219],{"align":5467},[3438,14220,14221],{},"asyncio.wait",[5465,14223,14224],{"align":5467},[3438,14225,14226],{},"asyncio.as_completed",[5465,14228,14229],{"align":5467},[3438,14230,5093],{},[5480,14232,14233,14256,14284,14309,14334],{},[5462,14234,14235,14240,14243,14248,14250],{},[5485,14236,14237],{"align":5467},[3398,14238,14239],{},"Вимога до вхідних даних",[5485,14241,14242],{"align":5467},"Список будь-яких awaitables",[5485,14244,14245,14246],{"align":5467},"Множина об'єктів ",[3438,14247,6420],{},[5485,14249,14242],{"align":5467},[5485,14251,14252,14253],{"align":5467},"Створення задач через ",[3438,14254,14255],{},".create_task()",[5462,14257,14258,14263,14266,14273,14278],{},[5485,14259,14260],{"align":5467},[3398,14261,14262],{},"Повертане значення",[5485,14264,14265],{"align":5467},"Упорядкований список результатів",[5485,14267,14268,14269,3554,14271],{"align":5467},"Дві множини ",[3438,14270,7483],{},[3438,14272,7487],{},[5485,14274,14275,14276],{"align":5467},"Ітератор асинхронних ",[3438,14277,4337],{},[5485,14279,14280,14281],{"align":5467},"Результат кожної задачі отримується через ",[3438,14282,14283],{},"task.result()",[5462,14285,14286,14291,14294,14300,14303],{},[5485,14287,14288],{"align":5467},[3398,14289,14290],{},"Поведінка при помилці",[5485,14292,14293],{"align":5467},"Скасування не відбувається автоматично",[5485,14295,14296,14297,14299],{"align":5467},"Залежить від ",[3438,14298,7513],{},", задачі не скасовуються",[5485,14301,14302],{"align":5467},"Обробка помилок вручну при отриманні результату",[5485,14304,14305,14308],{"align":5467},[3398,14306,14307],{},"Автоматичне скасування"," всіх інших задач групи",[5462,14310,14311,14316,14319,14324,14331],{},[5485,14312,14313],{"align":5467},[3398,14314,14315],{},"Поведінка при таймауті",[5485,14317,14318],{"align":5467},"Немає вбудованого таймауту",[5485,14320,14321,14322],{"align":5467},"Частково виконані задачі залишаються в ",[3438,14323,7487],{},[5485,14325,14326,14327,14330],{"align":5467},"Викидає ",[3438,14328,14329],{},"TimeoutError"," при ітерації",[5485,14332,14333],{"align":5467},"Скасовує всі невиконані задачі групи",[5462,14335,14336,14341,14344,14347,14349],{},[5485,14337,14338],{"align":5467},[3398,14339,14340],{},"Концепція архітектури",[5485,14342,14343],{"align":5467},"Неструктурована",[5485,14345,14346],{"align":5467},"Напівструктурована",[5485,14348,14343],{"align":5467},[5485,14350,14351,14354],{"align":5467},[3398,14352,14353],{},"Структурована конкурентність"," (безпечна)",[3461,14356,14358,14359],{"id":14357},"ключові-принципи-роботи-з-asyncio","Ключові принципи роботи з ",[3438,14360,3451],{},[3422,14362,14363,14383,14399,14411,14420,14432],{},[3425,14364,14365,14370,14371,14374,14375,14378,14379,4313,14381,3507],{},[3398,14366,14367,14369],{},[3438,14368,3488],{}," сам по собі не створює паралельності",". Якщо ви пишете ",[3438,14372,14373],{},"await task1()"," і на наступному рядку ",[3438,14376,14377],{},"await task2()",", вони виконуватимуться суворо послідовно. Для конкурентного виконання використовуйте ",[3438,14380,12173],{},[3438,14382,8320],{},[3425,14384,14385,14388,14389,4890,14391,4890,14393,14396,14397,3507],{},[3398,14386,14387],{},"Неблокуюче виконання",". Будь-який блокуючий виклик (",[3438,14390,10908],{},[3438,14392,10911],{},[3438,14394,14395],{},"urllib.request.urlopen()",", синхронні драйвери баз даних) зупиняє весь подієвий цикл. Використовуйте асинхронні бібліотеки або виносьте синхронний код через ",[3438,14398,11514],{},[3425,14400,14401,14404,14405,14407,14408,14410],{},[3398,14402,14403],{},"Обробка таймаутів",". Завжди лімітуйте час очікування для мережевих викликів. Застосовуйте ",[3438,14406,10394],{}," у Python 3.11+ для блоків коду та ",[3438,14409,10397],{}," для поодиноких задач.",[3425,14412,14413,14416,14417,14419],{},[3398,14414,14415],{},"Використання семафорів для захисту від перевантажень",". Завжди обмежуйте кількість конкурентних мережевих запитів за допомогою ",[3438,14418,9000],{},", щоб уникнути блокувань з боку зовнішніх API (Rate Limiting).",[3425,14421,14422,14425,14426,14428,14429,14431],{},[3398,14423,14424],{},"Один Event Loop на додаток",". Метод ",[3438,14427,6184],{}," має викликатися рівно один раз на самому верхньому рівні програми (як точка входу). Не викликайте ",[3438,14430,6184],{}," всередині асинхронних функцій.",[3425,14433,14434,14439,14440,8644,14442,14444],{},[3398,14435,14436,14437],{},"Пріоритет ",[3438,14438,8320],{},". У коді на Python 3.11+ віддавайте перевагу менеджеру контексту ",[3438,14441,5093],{},[3438,14443,4694],{}," для підвищення надійності та автоматичного скасування невикористаних фонових задач.",[14446,14447,14448],"style",{},"html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}",{"title":3569,"searchDepth":3583,"depth":3583,"links":14450},[14451,14454,14460,14469,14482,14494,14498,14508,14509],{"id":3391,"depth":3583,"text":3392,"children":14452},[14453],{"id":3463,"depth":3594,"text":3464},{"id":3512,"depth":3583,"text":3513,"children":14455},[14456,14457,14458],{"id":3516,"depth":3594,"text":3517},{"id":3738,"depth":3594,"text":3739},{"id":4255,"depth":3594,"text":14459},"Що відбувається у точці await (Глибинний аналіз життєвого циклу корутини)",{"id":5098,"depth":3583,"text":14461,"children":14462},"Частина II: async def і await — синтаксис і семантика",[14463,14464,14465,14467],{"id":5117,"depth":3594,"text":5118},{"id":5439,"depth":3594,"text":5440},{"id":5864,"depth":3594,"text":14466},"Що можна await (Протокол Awaitable)",{"id":6181,"depth":3594,"text":14468},"asyncio.run() — правильна точка входу",{"id":6416,"depth":3583,"text":14470,"children":14471},"Частина III: Task і Future — конкурентне виконання",[14472,14474,14476,14478,14480],{"id":6442,"depth":3594,"text":14473},"asyncio.create_task() — планування та запуск задачі",{"id":6923,"depth":3594,"text":14475},"asyncio.gather() — конкурентне агрегування результатів",{"id":7463,"depth":3594,"text":14477},"asyncio.wait() — тонке керування життєвим циклом групи задач",{"id":8048,"depth":3594,"text":14479},"asyncio.as_completed() — обробка результатів по мірі готовності",{"id":8306,"depth":3594,"text":14481},"asyncio.TaskGroup — структурована конкурентність (Python 3.11+)",{"id":8652,"depth":3583,"text":8653,"children":14483},[14484,14486,14488,14490,14492],{"id":8669,"depth":3594,"text":14485},"asyncio.Lock — взаємне виключення (Mutex)",{"id":8997,"depth":3594,"text":14487},"asyncio.Semaphore — обмеження кількості конкурентних операцій",{"id":9456,"depth":3594,"text":14489},"asyncio.Event — асинхронна сигналізація між корутинами",{"id":9838,"depth":3594,"text":14491},"asyncio.Queue — асинхронна черга для патерну Producer-Consumer",{"id":10390,"depth":3594,"text":14493},"Таймаути: asyncio.timeout() та asyncio.wait_for()",{"id":10898,"depth":3583,"text":10899,"children":14495},[14496],{"id":10929,"depth":3594,"text":14497},"loop.run_in_executor() — виконання блокуючого коду без зупинки Event Loop",{"id":11532,"depth":3583,"text":11533,"children":14499},[14500,14501,14503,14505,14507],{"id":11539,"depth":3594,"text":11540},{"id":11711,"depth":3594,"text":14502},"Антипатерн 2: Забутий await",{"id":11878,"depth":3594,"text":14504},"Антипатерн 3: Послідовний await замість конкурентного виконання",{"id":12061,"depth":3594,"text":14506},"Антипатерн 4: Виклик asyncio.run() у вже запущеному Event Loop",{"id":12163,"depth":3594,"text":12164},{"id":12285,"depth":3583,"text":12286},{"id":13914,"depth":3583,"text":13915,"children":14510},[14511,14512,14513],{"id":13918,"depth":3594,"text":13919},{"id":14202,"depth":3594,"text":14203},{"id":14357,"depth":3594,"text":14514},"Ключові принципи роботи з asyncio","Вичерпний розбір asyncio у Python — від моделі event loop і корутин до Task, Future, примітивів синхронізації, таймаутів та інтеграції з синхронним кодом. Практичні патерни для побудови масштабованих асинхронних програм.","md",null,{},{"title":2605,"description":14515},"Lfxiw_vn6u8Y6ODId8W7Ummb61xuqhc2kdIizx8B9PA",[14522,14524],{"title":2601,"path":2602,"stem":2603,"description":14523,"children":-1},"Вичерпний розбір модуля multiprocessing у Python — від Process і методів запуску до Pool, ProcessPoolExecutor, міжпроцесної комунікації (Queue, Pipe, shared_memory), проблеми pickling та реальних прикладів паралельної обробки даних.",{"title":2614,"path":2615,"stem":2616,"description":14525,"children":-1},"Дослідження статичної типізації в сучасній екосистемі Python, пристрій Pydantic v2 та перехід від інспекції типів до автоматичної валідації даних.",1783248147417]