LevelUpWith

Explore / Technology

Legacy to Parallel: C# and Python Cloud Migrations

Illustrated cover for the course “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

  1. Level 1: Define the Migration Evidence ContractFree
    Define what a successful migration must prove before changing a calculation that runs for hours or days.
  2. 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.
  3. 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.
  4. 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.
  5. 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/).
  6. 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.
  7. 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.
  8. Level 8: Diagnose Lock Contention
    Identify synchronization that serializes existing workers and distinguish contention from ordinary I/O waiting.
  9. 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).
  10. Level 10: Recognize Memory Bandwidth Limits
    Test whether moving data through memory limits a calculation even when its arithmetic appears easy to parallelize.
  11. 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.
  12. 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.
  13. Level 13: Capture Legacy Behavior with Characterization Tests
    Turn observed C# and Python behavior into regression fixtures before altering the calculation's structure.
  14. Level 14: Specify Numerical Acceptance
    Define comparison rules that detect meaningful calculation changes without assuming every floating-point result must match bit for bit.
  15. Level 15: Make Randomness an Explicit Dependency
    Replace hidden random-number consumption with a recorded reproducibility contract that can survive later changes in scheduling.
  16. Level 16: Define the Calculation Kernel Contract
    Design a narrow input-and-output boundary that exposes everything the calculation needs before moving its code.
  17. 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.
  18. 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.
  19. Level 19: Remove Hidden Inputs Incrementally
    Eliminate ambient dependencies one at a time so repeated kernel calls depend on their declared inputs.
  20. Level 20: Give Inputs and Results Clear Ownership
    Prevent callers and kernels from changing each other's data through shared mutable references.
  21. Level 21: Define Numerical Acceptance
    Define which numerical differences are acceptable before changing how the extracted C# and Python kernels execute.
  22. Level 22: Make Random Streams Reproducible
    Make stochastic calculations reproducible by assigning random streams to stable logical work identities.
  23. 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.
  24. Level 24: Validate Native Dependency Contracts
    Make native libraries an explicit, testable part of the kernel's deployment contract.
  25. Level 25: Bound C# CPU Parallelism
    Run independent C# kernel calls concurrently while keeping worker demand within measured CPU and memory capacity.
  26. Level 26: Separate C# Async I/O from CPU Work
    Keep asynchronous data access from consuming the thread capacity needed for calculation.
  27. Level 27: Build a Bounded C# Worker Pipeline
    Use a bounded in-process queue to keep input production from overwhelming long-running calculation workers.
  28. Level 28: Handle Local Worker Failure and Shutdown
    Give local C# workers a defined lifecycle when a calculation fails or the operator requests cancellation.
  29. 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.
  30. 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.
  31. Level 31: Launch Portable Python Process Workers
    Execute CPU-bound Python kernels in processes with an explicit, portable startup contract.
  32. Level 32: Measure the Process Serialization Tax
    Determine whether moving inputs and outputs between Python processes costs more than the computation it enables.
  33. Level 33: Share Large Python Arrays Safely
    Reduce repeated array copying with shared memory while making ownership and cleanup explicit.
  34. Level 34: Control Nested Native Parallelism
    Prevent process pools and native numerical libraries from competing through excessive nested thread creation.
  35. Level 35: Vectorize Before Adding Workers
    Reduce per-element interpreter and loop overhead before spending resources on additional workers.
  36. Level 36: Find the GPU Break-Even Point
    Evaluate a GPU candidate using complete execution costs rather than kernel timing alone.
  37. Level 37: Recognize Workloads That Need HPC
    Identify calculations whose frequent cross-worker communication calls for tightly coupled compute rather than independent function invocations.
  38. Level 38: Prove the Single-Machine Scaling Ceiling
    Use the best local implementation to establish whether adding machines addresses a remaining bottleneck.
  39. Level 39: Define Distributed Work Partitions
    Turn eligible kernel inputs into independently addressable partitions with explicit coverage and ownership.
  40. Level 40: Choose Chunk Size from Measurements
    Balance dispatch overhead, memory use and uneven calculation duration by measuring distributed work granularity.
  41. Level 41: Schedule Dependencies as a DAG
    Turn extracted calculation stages into a dependency graph so workers execute only when their inputs are ready.
  42. Level 42: Reduce Results Without Numerical Surprises
    Combine partition results without letting execution order silently change the accepted numerical answer.
  43. 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.
  44. 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.
  45. Level 45: Commit Results Idempotently
    Prevent duplicate executions from publishing conflicting results by making result publication a conditional, verifiable operation.
  46. Level 46: Retry Within a Failure Budget
    Recover from temporary failures without multiplying load, rerunning invalid inputs indefinitely or hiding permanent defects.
  47. Level 47: Resume From Verified Checkpoints
    Save enough durable calculation state to resume hours of work without restarting or changing the answer.
  48. Level 48: Cancel Work Across Process Boundaries
    Propagate cancellation through distributed workers while preventing late attempts from committing results after cancellation.
  49. Level 49: Apply Backpressure Before Scaling
    Bound admitted and in-flight work so adding workers does not overload storage, databases or downstream APIs.
  50. Level 50: Recover the Slow Tail
    Reduce completion delays caused by unusually slow partitions without paying for uncontrolled duplicate work.
  51. Level 51: Persist Workflow Progress
    Move coordination out of a long-lived controller process into durable workflow state that survives controller restarts.
  52. Level 52: Recognize Work That Needs Tight Coupling
    Identify calculations whose communication and synchronization costs make independent cloud workers a poor fit.
  53. Level 53: Choose Compute From Workload Evidence
    Select functions, batch workers or clustered containers from measured workload requirements and documented service constraints.
  54. 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.
  55. 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.
  56. Level 56: Run Partitioned Cloud Run Jobs
    Execute a finite calculation as indexed container tasks with task count and simultaneous execution controlled separately.
  57. 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.
  58. Level 58: Control Calculation Jobs on GKE
    Run calculation workers as Kubernetes Jobs when placement and cluster control justify the operational overhead.
  59. 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.
  60. Level 60: Orchestrate Workers With Durable Functions
    Coordinate calculation activities through replay-safe Durable Functions orchestration while keeping computation outside orchestrator code.
  61. 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.
  62. Level 62: Fit Calculation Chunks into AWS Lambda
    Decide whether a bounded calculation chunk belongs in Lambda by testing its actual invocation envelope.
  63. 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.
  64. Level 64: Schedule Independent Partitions with AWS Batch
    Translate a partition manifest into an AWS Batch array job rather than managing individual worker launches.
  65. Level 65: Choose ECS Tasks or Persistent Workers
    Select between finite ECS tasks and persistent queue consumers according to worker lifetime and startup overhead.
  66. 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.
  67. 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.
  68. 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.
  69. 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.
  70. Level 70: Reproduce the Compute Environment with IaC
    Make the calculation environment reproducible through reviewed infrastructure definitions and pinned deployment inputs.
  71. 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.
  72. 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.
  73. Level 73: Compare Clouds with One Work Contract
    Compare deployment options fairly by holding calculation inputs, output contracts and acceptance criteria constant.
  74. Level 74: Prove Full-Run Numerical Correctness
    Establish that distributed execution preserves the calculation's accepted answers across complete datasets and deployment variants.
  75. Level 75: Prove End-to-End Speedup
    Measure whether the complete migrated calculation finishes sooner once scheduling, transfer and aggregation are included.
  76. Level 76: Calculate Cost per Accepted Result
    Determine whether faster execution delivers acceptable total cost after unsuccessful work and supporting services are counted.
  77. 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.
  78. Level 78: Test the Capacity Envelope
    Establish the largest reliable operating envelope by testing realistic concurrent runs and uneven partition durations.
  79. Level 79: Rehearse Staged Cutover and Rollback
    Move production work incrementally while preserving a tested route back to the legacy calculation.
  80. 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.

Start free →