From 9cbf047f63621bde1839dd3c830b2bad9dfbdfc6 Mon Sep 17 00:00:00 2001 From: cathyzbn Date: Fri, 9 Aug 2024 19:20:00 +0000 Subject: [PATCH 1/4] batching ascii example --- 03_scaling_out/dynamic_batching.py | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 03_scaling_out/dynamic_batching.py diff --git a/03_scaling_out/dynamic_batching.py b/03_scaling_out/dynamic_batching.py new file mode 100644 index 000000000..41bb982bc --- /dev/null +++ b/03_scaling_out/dynamic_batching.py @@ -0,0 +1,85 @@ +# # Dynamic batching for ASCII and character conversion +# +# This example demonstrates how dynamic batching can be used in a simple +# application for converting ASCII codes to characters and vice versa. +# +# For more details about using dynamic batching and tuning its configuration, see +# the [Dynamic Batching](/docs/guide/dynamic-batching) guide. +# +# ## Setup +# +# First, let's define the image for the application. + +import modal + +app = modal.App( + "example-dynamic-batching-ascii-conversion", + image=modal.Image.debian_slim() +) + +# ## The batched function +# +# Now, let's define a Function that converts ASCII codes to characters. This +# async batched Function allows us to convert at most four ASCII codes at once. +# If there are fewer than four ASCII codes in the batch, the function will wait +# for one second to allow more inputs to arrive before returning the result. +# +# In the function signature, the input `asciis` is a list of integers, and the +# output is a list of strings. This is because the `asciis` input is batched, +# and the output should be a list of the same length as the input. +# +# When the function is invoked, however, the input will be a single integer, +# and the return value to the invocation will be a single string. + +@app.function() +@modal.batched(max_batch_size=4, wait_ms=1000) +async def asciis_to_chars(asciis: list[int]) -> list[str]: + return [chr(ascii) for ascii in asciis] + + +# ## The Class with a batched method +# +# Next, let's define a Class that converts characters to ASCII codes. This +# Class has an async batched method `chars_to_asiics` that converts characters +# to ASCII codes and has the same configuration as the batched Function above. +# +# Note that if a Class has a batched method, the Class cannot implement other +# batched methods or `@modal.method`s. + + +@app.cls() +class AsciiConverter: + @modal.batched(max_batch_size=4, wait_ms=1000) + async def chars_to_asciis(self, chars: list[str]) -> list[int]: + asciis = [ord(char) for char in chars] + return asciis + + +# ## ASCII and character conversion +# +# Finally, let's define the `local_entrypoint` that uses the batched Function +# and the Class with a batched method to convert ASCII codes to characters and +# vice versa. +# +# We use [`map.aio`](/docs/reference/modal.Function#map) to asynchronously map +# over the ASCII codes and characters. This allows us to invoke the batched +# Function and the batched method over a range of ASCII codes and characters +# in parallel. +# +# Run this script to see what ASCII codes from 33 to 38 correspond to in characters! + + +@app.local_entrypoint() +async def main(): + ascii_converter = AsciiConverter() + chars = [] + async for char in asciis_to_chars.map.aio(range(33, 39)): + chars.append(char) + + print("Characters:", chars) + + asciis = [] + async for ascii in ascii_converter.chars_to_asciis.map.aio(chars): + asciis.append(ascii) + + print("ASCII codes:", asciis) From 230909f90cc34cceccb2f2ea325eb103b7b3ec18 Mon Sep 17 00:00:00 2001 From: cathyzbn Date: Thu, 15 Aug 2024 20:40:56 +0000 Subject: [PATCH 2/4] nit --- 03_scaling_out/dynamic_batching.py | 58 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/03_scaling_out/dynamic_batching.py b/03_scaling_out/dynamic_batching.py index 41bb982bc..2f0362c92 100644 --- a/03_scaling_out/dynamic_batching.py +++ b/03_scaling_out/dynamic_batching.py @@ -1,35 +1,37 @@ # # Dynamic batching for ASCII and character conversion # -# This example demonstrates how dynamic batching can be used in a simple -# application for converting ASCII codes to characters and vice versa. +# This example demonstrates how to dynamically batch a simple +# application to converts ASCII codes to characters and vice versa. # -# For more details about using dynamic batching and tuning its configuration, see -# the [Dynamic Batching](/docs/guide/dynamic-batching) guide. +# For more details about using dynamic batching and optimizing +# the batching configurations for your application, see +# the [dynamic batching guide](https://modal.com/docs/guide/dynamic-batching). # # ## Setup # -# First, let's define the image for the application. +# Let's start by defining the image for the application. import modal app = modal.App( - "example-dynamic-batching-ascii-conversion", - image=modal.Image.debian_slim() + "example-dynamic-batching-ascii-conversion", image=modal.Image.debian_slim() ) -# ## The batched function +# ## Defining a Batched Function # -# Now, let's define a Function that converts ASCII codes to characters. This -# async batched Function allows us to convert at most four ASCII codes at once. -# If there are fewer than four ASCII codes in the batch, the function will wait -# for one second to allow more inputs to arrive before returning the result. +# Now, let's define a function that converts ASCII codes to characters. This +# async Batched Function allows us to convert up to four ASCII codes at once. +# If there are fewer than four ASCII codes in the batch, the Function will wait +# for one second, as specified by `wait_ms`, to allow more inputs to arrive before +# returning the result. # -# In the function signature, the input `asciis` is a list of integers, and the -# output is a list of strings. This is because the `asciis` input is batched, -# and the output should be a list of the same length as the input. +# The input `asciis` to the Function is a list of integers, and the +# output is a list of strings. To allow batching, the input list `asciis` +# and the output list must have the same length. # -# When the function is invoked, however, the input will be a single integer, -# and the return value to the invocation will be a single string. +# However, you must invoke the Function with an individual ASCII input, and a single +# character will be returned to the invocation. + @app.function() @modal.batched(max_batch_size=4, wait_ms=1000) @@ -37,14 +39,14 @@ async def asciis_to_chars(asciis: list[int]) -> list[str]: return [chr(ascii) for ascii in asciis] -# ## The Class with a batched method +# ## Defining a class with a Batched Method # -# Next, let's define a Class that converts characters to ASCII codes. This -# Class has an async batched method `chars_to_asiics` that converts characters -# to ASCII codes and has the same configuration as the batched Function above. +# Next, let's define a class that converts characters to ASCII codes. This +# class has an async Batched Method `chars_to_asciis` that converts characters +# to ASCII codes. # -# Note that if a Class has a batched method, the Class cannot implement other -# batched methods or `@modal.method`s. +# Note that if a class has a Batched Method, it cannot have other Batched Methods +# or Methods. @app.cls() @@ -57,16 +59,16 @@ async def chars_to_asciis(self, chars: list[str]) -> list[int]: # ## ASCII and character conversion # -# Finally, let's define the `local_entrypoint` that uses the batched Function -# and the Class with a batched method to convert ASCII codes to characters and +# Finally, let's define the `local_entrypoint` that uses the Batched Function +# and Class Method to convert ASCII codes to characters and # vice versa. # # We use [`map.aio`](/docs/reference/modal.Function#map) to asynchronously map -# over the ASCII codes and characters. This allows us to invoke the batched -# Function and the batched method over a range of ASCII codes and characters +# over the ASCII codes and characters. This allows us to invoke the Batched +# Function and the Batched Method over a range of ASCII codes and characters # in parallel. # -# Run this script to see what ASCII codes from 33 to 38 correspond to in characters! +# Run this script to see which characters correspond to ASCII codes 33 through 38! @app.local_entrypoint() From 023b0924e3278d918af33a4d1ad5fe00e0d7e48f Mon Sep 17 00:00:00 2001 From: cathyzbn Date: Tue, 20 Aug 2024 15:18:37 +0000 Subject: [PATCH 3/4] nit --- 03_scaling_out/dynamic_batching.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/03_scaling_out/dynamic_batching.py b/03_scaling_out/dynamic_batching.py index 2f0362c92..254f00aa5 100644 --- a/03_scaling_out/dynamic_batching.py +++ b/03_scaling_out/dynamic_batching.py @@ -1,7 +1,7 @@ # # Dynamic batching for ASCII and character conversion # # This example demonstrates how to dynamically batch a simple -# application to converts ASCII codes to characters and vice versa. +# application that converts ASCII codes to characters and vice versa. # # For more details about using dynamic batching and optimizing # the batching configurations for your application, see @@ -17,6 +17,7 @@ "example-dynamic-batching-ascii-conversion", image=modal.Image.debian_slim() ) + # ## Defining a Batched Function # # Now, let's define a function that converts ASCII codes to characters. This @@ -29,9 +30,8 @@ # output is a list of strings. To allow batching, the input list `asciis` # and the output list must have the same length. # -# However, you must invoke the Function with an individual ASCII input, and a single -# character will be returned to the invocation. - +# You must invoke the Function with an individual ASCII input, and a single +# character will be returned in response. @app.function() @modal.batched(max_batch_size=4, wait_ms=1000) @@ -48,7 +48,6 @@ async def asciis_to_chars(asciis: list[int]) -> list[str]: # Note that if a class has a Batched Method, it cannot have other Batched Methods # or Methods. - @app.cls() class AsciiConverter: @modal.batched(max_batch_size=4, wait_ms=1000) @@ -70,7 +69,6 @@ async def chars_to_asciis(self, chars: list[str]) -> list[int]: # # Run this script to see which characters correspond to ASCII codes 33 through 38! - @app.local_entrypoint() async def main(): ascii_converter = AsciiConverter() From ebca91f6fb79865777020dc4e7ce9b82b4dec25b Mon Sep 17 00:00:00 2001 From: cathyzbn Date: Tue, 20 Aug 2024 15:19:25 +0000 Subject: [PATCH 4/4] format --- 03_scaling_out/dynamic_batching.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/03_scaling_out/dynamic_batching.py b/03_scaling_out/dynamic_batching.py index 254f00aa5..17b7b7588 100644 --- a/03_scaling_out/dynamic_batching.py +++ b/03_scaling_out/dynamic_batching.py @@ -33,6 +33,7 @@ # You must invoke the Function with an individual ASCII input, and a single # character will be returned in response. + @app.function() @modal.batched(max_batch_size=4, wait_ms=1000) async def asciis_to_chars(asciis: list[int]) -> list[str]: @@ -48,6 +49,7 @@ async def asciis_to_chars(asciis: list[int]) -> list[str]: # Note that if a class has a Batched Method, it cannot have other Batched Methods # or Methods. + @app.cls() class AsciiConverter: @modal.batched(max_batch_size=4, wait_ms=1000) @@ -69,6 +71,7 @@ async def chars_to_asciis(self, chars: list[str]) -> list[int]: # # Run this script to see which characters correspond to ASCII codes 33 through 38! + @app.local_entrypoint() async def main(): ascii_converter = AsciiConverter()