Explore / Technology
Legacy to Parallel: C# and Python Cloud Migrations

Turn calculations lasting hours or days into tested parallel kernels and resilient cloud workers through worked C# and Python migrations. Prove numerical correctness, end-to-end speedup and cost across GCP, Azure and AWS, with each 15-minute lesson and advancement quiz grounded in current documentat
Expert · 80 levels · 2 free · Created Oct 2026 · Professionally curated by levelupwith.com
What's inside
- Level 1: Define the Migration Evidence ContractFree
Define what a successful migration must prove before changing a calculation that runs for hours or days. - Level 2: Map the Repository with Verifiable AI AssistanceFree
Use an AI coding tool to trace calculation entry points and dependencies while checking every architectural claim against repository evidence. - Level 3: Trace Mutable State and Hidden Coupling
Identify the shared state and side effects that can make apparently independent calculations depend on execution order. - Level 4: Build a Representative Measurement Harness
Create repeatable measurements that preserve realistic workload characteristics without requiring a full multi-day run for every experiment. - Level 5: Find C# CPU Hotspots
Locate expensive C# call paths using tools selected from the installed runtime's [diagnostics documentation](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/). - Level 6: Find Python CPU Hotspots
Use [cProfile and pstats](https://docs.python.org/3/library/profile.html) to locate expensive Python call paths and recognize when native work needs additional evidence. - Level 7: Separate I/O Waiting from Computation
Explain low CPU utilization by measuring file, database and network waits rather than assuming the calculation needs more workers. - Level 8: Diagnose Lock Contention
Identify synchronization that serializes existing workers and distinguish contention from ordinary I/O waiting. - Level 9: Explain Allocation and Memory Pressure
Connect allocation patterns and retained objects to runtime using [.NET counters](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters) and [Python tracemalloc](https://docs.python.org/3/library/tracemalloc.html). - Level 10: Recognize Memory Bandwidth Limits
Test whether moving data through memory limits a calculation even when its arithmetic appears easy to parallelize. - Level 11: Bound Speedup with the Serial Fraction
Translate [Amdahl's law](https://www.intel.com/content/www/us/en/docs/advisor/user-guide/2024-0/use-amdahl-law.html) into a small executable model that bounds improvement for a fixed workload. - Level 12: Compare Speedup, Efficiency and Cost
Use an experiment ledger to decide whether a faster execution plan delivers enough benefit for its total resource cost. - Level 13: Capture Legacy Behavior with Characterization Tests
Turn observed C# and Python behavior into regression fixtures before altering the calculation's structure. - Level 14: Specify Numerical Acceptance
Define comparison rules that detect meaningful calculation changes without assuming every floating-point result must match bit for bit. - Level 15: Make Randomness an Explicit Dependency
Replace hidden random-number consumption with a recorded reproducibility contract that can survive later changes in scheduling. - Level 16: Define the Calculation Kernel Contract
Design a narrow input-and-output boundary that exposes everything the calculation needs before moving its code. - Level 17: Extract a C# Kernel Behind the Legacy Entry Point
Move one C# calculation into the explicit contract while keeping the existing caller operational. - Level 18: Extract a Python Kernel Without Import Side Effects
Move one Python calculation into an importable function whose execution is controlled by its caller. - Level 19: Remove Hidden Inputs Incrementally
Eliminate ambient dependencies one at a time so repeated kernel calls depend on their declared inputs. - Level 20: Give Inputs and Results Clear Ownership
Prevent callers and kernels from changing each other's data through shared mutable references. - Level 21: Define Numerical Acceptance
Define which numerical differences are acceptable before changing how the extracted C# and Python kernels execute. - Level 22: Make Random Streams Reproducible
Make stochastic calculations reproducible by assigning random streams to stable logical work identities. - Level 23: Find the .NET Portability Boundary
Determine which legacy .NET components can move to a modern worker runtime and which require a Windows boundary. - Level 24: Validate Native Dependency Contracts
Make native libraries an explicit, testable part of the kernel's deployment contract. - Level 25: Bound C# CPU Parallelism
Run independent C# kernel calls concurrently while keeping worker demand within measured CPU and memory capacity. - Level 26: Separate C# Async I/O from CPU Work
Keep asynchronous data access from consuming the thread capacity needed for calculation. - Level 27: Build a Bounded C# Worker Pipeline
Use a bounded in-process queue to keep input production from overwhelming long-running calculation workers. - Level 28: Handle Local Worker Failure and Shutdown
Give local C# workers a defined lifecycle when a calculation fails or the operator requests cancellation. - Level 29: Identify Python's Actual GIL Behavior
Choose a Python concurrency strategy from the running interpreter and imported extensions rather than assumptions about the GIL. - Level 30: Use Python Threads Where They Help
Apply a bounded Python thread pool to operations whose waiting or native execution can benefit from concurrency. - Level 31: Launch Portable Python Process Workers
Execute CPU-bound Python kernels in processes with an explicit, portable startup contract. - Level 32: Measure the Process Serialization Tax
Determine whether moving inputs and outputs between Python processes costs more than the computation it enables. - Level 33: Share Large Python Arrays Safely
Reduce repeated array copying with shared memory while making ownership and cleanup explicit. - Level 34: Control Nested Native Parallelism
Prevent process pools and native numerical libraries from competing through excessive nested thread creation. - Level 35: Vectorize Before Adding Workers
Reduce per-element interpreter and loop overhead before spending resources on additional workers. - Level 36: Find the GPU Break-Even Point
Evaluate a GPU candidate using complete execution costs rather than kernel timing alone. - Level 37: Recognize Workloads That Need HPC
Identify calculations whose frequent cross-worker communication calls for tightly coupled compute rather than independent function invocations. - Level 38: Prove the Single-Machine Scaling Ceiling
Use the best local implementation to establish whether adding machines addresses a remaining bottleneck. - Level 39: Define Distributed Work Partitions
Turn eligible kernel inputs into independently addressable partitions with explicit coverage and ownership. - Level 40: Choose Chunk Size from Measurements
Balance dispatch overhead, memory use and uneven calculation duration by measuring distributed work granularity. - Level 41: Schedule Dependencies as a DAG
Turn extracted calculation stages into a dependency graph so workers execute only when their inputs are ready. - Level 42: Reduce Results Without Numerical Surprises
Combine partition results without letting execution order silently change the accepted numerical answer. - Level 43: Keep Compute Close to Its Data
Design worker input placement so serialization, repeated downloads and cross-region transfers do not consume the expected speedup. - Level 44: Dispatch Work Through Queue Leases
Use competing consumers to distribute work while treating message ownership as temporary and redelivery as an expected condition. - Level 45: Commit Results Idempotently
Prevent duplicate executions from publishing conflicting results by making result publication a conditional, verifiable operation. - Level 46: Retry Within a Failure Budget
Recover from temporary failures without multiplying load, rerunning invalid inputs indefinitely or hiding permanent defects. - Level 47: Resume From Verified Checkpoints
Save enough durable calculation state to resume hours of work without restarting or changing the answer. - Level 48: Cancel Work Across Process Boundaries
Propagate cancellation through distributed workers while preventing late attempts from committing results after cancellation. - Level 49: Apply Backpressure Before Scaling
Bound admitted and in-flight work so adding workers does not overload storage, databases or downstream APIs. - Level 50: Recover the Slow Tail
Reduce completion delays caused by unusually slow partitions without paying for uncontrolled duplicate work. - Level 51: Persist Workflow Progress
Move coordination out of a long-lived controller process into durable workflow state that survives controller restarts. - Level 52: Recognize Work That Needs Tight Coupling
Identify calculations whose communication and synchronization costs make independent cloud workers a poor fit. - Level 53: Choose Compute From Workload Evidence
Select functions, batch workers or clustered containers from measured workload requirements and documented service constraints. - Level 54: Package Workers With Resource Limits
Build reproducible C# and Python worker images that behave correctly under the CPU and memory allocations they will receive. - Level 55: Use Cloud Run Services for Bounded Requests
Deploy a bounded request-driven calculation and establish when request execution should give way to asynchronous work. - Level 56: Run Partitioned Cloud Run Jobs
Execute a finite calculation as indexed container tasks with task count and simultaneous execution controlled separately. - Level 57: Schedule VM-Based Work With GCP Batch
Use GCP Batch when a calculation needs explicitly selected VM resources and managed scheduling of finite tasks. - Level 58: Control Calculation Jobs on GKE
Run calculation workers as Kubernetes Jobs when placement and cluster control justify the operational overhead. - Level 59: Fit Workers to Azure Functions Hosting
Match a bounded calculation to an Azure Functions trigger and hosting plan using their actual execution and scaling constraints. - Level 60: Orchestrate Workers With Durable Functions
Coordinate calculation activities through replay-safe Durable Functions orchestration while keeping computation outside orchestrator code. - Level 61: Run Finite Workers with Azure Container Apps Jobs
Deploy a containerized calculation as a finite Azure job with execution settings that match its work contract. - Level 62: Fit Calculation Chunks into AWS Lambda
Decide whether a bounded calculation chunk belongs in Lambda by testing its actual invocation envelope. - Level 63: Coordinate Long Runs with AWS Step Functions
Coordinate an hours-long calculation through a workflow whose lifetime is separate from its workers' execution limits. - Level 64: Schedule Independent Partitions with AWS Batch
Translate a partition manifest into an AWS Batch array job rather than managing individual worker launches. - Level 65: Choose ECS Tasks or Persistent Workers
Select between finite ECS tasks and persistent queue consumers according to worker lifetime and startup overhead. - Level 66: Run Indexed Jobs on GKE, AKS and EKS
Use Kubernetes Jobs when calculation workers need cluster scheduling control that justifies operating a cluster. - Level 67: Tune Workers to Container Resource Budgets
Align internal C# and Python concurrency with the CPU and memory resources actually available to each container. - Level 68: Scale Against Capacity and Downstream Limits
Control fleet growth using queue pressure, available quota and downstream throughput rather than an unlimited worker target. - Level 69: Trace a Calculation Across Worker Boundaries
Instrument a calculation so operators can locate time and failures across submission, queues, workers and result commits. - Level 70: Reproduce the Compute Environment with IaC
Make the calculation environment reproducible through reviewed infrastructure definitions and pinned deployment inputs. - Level 71: Worked C# Migration: Deploy the Extracted Kernel
Complete a worked C# migration by packaging an already-tested calculation kernel as a cloud batch worker. - Level 72: Worked Python Migration: Deploy Process Workers
Complete a worked Python migration by running a bounded local process pool inside each GCP Batch task. - Level 73: Compare Clouds with One Work Contract
Compare deployment options fairly by holding calculation inputs, output contracts and acceptance criteria constant. - Level 74: Prove Full-Run Numerical Correctness
Establish that distributed execution preserves the calculation's accepted answers across complete datasets and deployment variants. - Level 75: Prove End-to-End Speedup
Measure whether the complete migrated calculation finishes sooner once scheduling, transfer and aggregation are included. - Level 76: Calculate Cost per Accepted Result
Determine whether faster execution delivers acceptable total cost after unsuccessful work and supporting services are counted. - Level 77: Inject Failures into the Complete Migration
Validate recovery guarantees by disrupting the assembled system at the points where work or results could be lost. - Level 78: Test the Capacity Envelope
Establish the largest reliable operating envelope by testing realistic concurrent runs and uneven partition durations. - Level 79: Rehearse Staged Cutover and Rollback
Move production work incrementally while preserving a tested route back to the legacy calculation. - Level 80: Final Challenge: Defend the Complete Migration Exam
Review the whole course by defending a complete C# and Python migration with reproducible correctness, performance, cost and operational evidence.
Access
The first 2 levels are free with a free account. Every level, the podcast edition and the AI tutor come with All Access at £4.99/month or any Creator plan — see pricing.