Skip to content

Commit ecbcd9d

Browse files
committed
EDU-4430 fixing lints
1 parent e0c7630 commit ecbcd9d

File tree

1 file changed

+32
-32
lines changed

1 file changed

+32
-32
lines changed

docs/develop/python/python-sdk-sync-vs-async.mdx

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ into a synchronous program that executes serially, defeating the entire purpose
5656
of using `asyncio`. This can also lead to potential deadlock, and unpredictable behavior
5757
that causes tasks to be unable to execute. Debugging these issues can be difficult
5858
and time consuming, as locating the source of the blocking call might not always
59-
be immediately obvious.
59+
be immediately evident.
6060

6161
Due to this, Python developers must be extra careful to not make blocking calls
6262
from within an asynchronous Activity, or use an async safe library to perform
@@ -71,33 +71,33 @@ such as `aiohttp` or `httpx`. Otherwise, use a synchronous Activity.
7171

7272
Python workers have following components for executing code:
7373

74-
- Your event loop, which runs tasks from async activities **plus the rest of the Temporal Worker, such as communicating with the server**.
75-
- An executor for executing activity tasks from synchronous activities. A thread pool executor is recommended.
76-
- A thread pool executor for executing workflow tasks.
74+
- Your event loop, which runs Tasks from async Activities **plus the rest of the Temporal Worker, such as communicating with the server**.
75+
- An executor for executing Activity Tasks from synchronous Activities. A thread pool executor is recommended.
76+
- A thread pool executor for executing Workflow Tasks.
7777

7878
> See Also: [docs for](https://python.temporal.io/temporalio.worker.Worker.html#__init__) `worker.__init__()`
7979
8080
### Activities
8181

82-
- The activities and the temporal worker SDK code both run the default asyncio event loop or whatever event loop you give the Worker.
82+
- The Activities and the temporal worker SDK code both run the default asyncio event loop or whatever event loop you give the Worker.
8383
- Synchronous Activities run in the `activity_executor`.
8484

8585
### Workflows
8686

87-
Since workflow tasks (1) are CPU bound, (2) need to be timed out for deadlock detection, and (3) need to not block other workflow tasks, they are run in threads. The `workflow_task_executor` is the thread pool these tasks are run on.
87+
Since Workflow Tasks (1) are CPU bound, (2) need to be timed out for deadlock detection, and (3) need to not block other Workflow Tasks, they are run in threads. The `workflow_task_executor` is the thread pool these Tasks are run on.
8888

8989
The fact that Workflow Tasks run in a thread pool can be confusing at first because Workflow Definitions are `async`.
90-
The key differentiator is that the `async` in Workflow Definitions is not referring to the standard event loop -- it is referring to the workflow's own event loop.
91-
Each workflow gets its own “workflow event loop”, which is deterministic, and described in [the Python SDK blog](https://temporal.io/blog/durable-distributed-asyncio-event-loop#temporal-workflows-are-asyncio-event-loops).
92-
The workflow event loop doesn't constantly loop -- it just gets cycled through during a workflow task to make as much progress as possible on all of its futures.
90+
The key differentiator is that the `async` in Workflow Definitions isn't referring to the standard event loop -- it's referring to the Workflow's own event loop.
91+
Each Workflow gets its own “Workflow event loop,” which is deterministic, and described in [the Python SDK blog](https://temporal.io/blog/durable-distributed-asyncio-event-loop#temporal-workflows-are-asyncio-event-loops).
92+
The Workflow event loop doesn't constantly loop -- it just gets cycled through during a Workflow Task to make as much progress as possible on all of its futures.
9393
When it can no longer make progress on any of its futures, then the Workflow Task is complete.
9494

9595
### Number of CPU cores
9696

9797
The only ways to use more than one core in a python worker (considering Python's GIL) are:
9898

9999
- Run more than one worker process.
100-
- Run the sync activities in a process pool executor, but a thread pool executor is recommended.
100+
- Run the synchronous Activities in a process pool executor, but a thread pool executor is recommended.
101101

102102
### Separating Activity and Workflow Workers
103103

@@ -106,30 +106,30 @@ some users choose to deploy separate Workers for Workflow Tasks and Activity Tas
106106

107107
## Activity Definition
108108

109-
**By default, activities should be synchronous rather than asynchronous**.
110-
You should only make an activity asynchronous if you are _very_
109+
**By default, Activities should be synchronous rather than asynchronous**.
110+
You should only make an Activity asynchronous if you are _very_
111111
sure that it does not block the event loop.
112112

113113
This is because if you have blocking code in an `async def` function,
114114
it blocks your event loop and the rest of Temporal, which can cause bugs that are
115-
very hard to diagnose, including freezing your worker and blocking workflow progress
116-
(because Temporal can't tell the server that workflow tasks are completing).
117-
The reason synchronous activities help is because they
115+
hard to diagnose, including freezing your worker and blocking Workflow progress
116+
(because Temporal can't tell the server that Workflow Tasks are completing).
117+
The reason synchronous Activities help is because they
118118
run in the `activity_executor` ([docs for](https://python.temporal.io/temporalio.worker.Worker.html#__init__) `worker.__init__()`)
119119
rather than in the global event loop,
120120
which helps because:
121121

122122
- There's no risk of accidentally blocking the global event loop.
123123
- If you have multiple
124-
activity tasks running in a thread pool rather than an event loop, one bad
125-
activity task can't slow down the others; this is because the OS scheduler preemptively
124+
Activity Tasks running in a thread pool rather than an event loop, one bad
125+
Activity Task can't slow down the others; this is because the OS scheduler preemptively
126126
switches between threads, which the event loop coordinator does not do.
127127

128128
> See Also:
129129
> ["Types of Activities" section of Python SDK README](https://github.com/temporalio/sdk-python#types-of-activities)
130130
> and [Sync vs Async activity implementations](https://docs.temporal.io/develop/python/python-sdk-sync-vs-async)
131131
132-
## Implementing Synchronous Activities
132+
## How to implement Synchronous Activities
133133

134134
The following code is a synchronous Activity Definition.
135135
It takes a name (`str`) as input and returns a
@@ -160,11 +160,11 @@ class TranslateActivities:
160160
return response.text
161161
```
162162

163-
In the above example we chose not to share a session across the Activity, so
163+
The preceeding example doesn't share a session across the Activity, so
164164
`__init__` was removed. While `requests` does have the ability to create sessions,
165-
it is currently unknown if they are thread safe. Due to no longer having or needing
165+
it's currently unknown if they are thread safe. Due to no longer having or needing
166166
`__init__`, the case could be made here to not implement the Activities as a class,
167-
but just as decorated functions as shown below:
167+
but just as decorated functions as shown here:
168168

169169
```python
170170
@activity.defn
@@ -181,14 +181,14 @@ def call_service(stem: str, name: str) -> str:
181181
return response.text
182182
```
183183

184-
Whether to implement Activities as class methods or functions is a design choice
185-
choice left up to the developer when cross-activity state is not needed. Both are
184+
Whether to implement Activities as class methods or functions is a design
185+
choice left up to the developer when cross-activity state isn't needed. Both are
186186
equally valid implementations.
187187

188-
### Worker for Synchronous Activities
188+
### How to run Synchronous Activities on a Worker
189189

190-
When running synchronous activities, the Worker
191-
neets to have an `activity_executor`. Temporal
190+
When running synchronous Activities, the Worker
191+
needs to have an `activity_executor`. Temporal
192192
recommends using a `ThreadPoolExecutor` as shown here:
193193

194194
```python
@@ -200,20 +200,20 @@ with ThreadPoolExecutor(max_workers=42) as executor:
200200
)
201201
```
202202

203-
## Implementing Asynchronous Activities
203+
## How to Implement Asynchronous Activities
204204

205-
The following code is an implementation of the above Activity, but as an
205+
The following code is an implementation of the preceeding Activity, but as an
206206
asynchronous Activity Definition.
207207

208208
It makes
209209
a call to a microservice, accessed through HTTP, to request this
210-
greeting in Spanish. This activity uses the `aiohttp` library to make an async
210+
greeting in Spanish. This Activity uses the `aiohttp` library to make an async
211211
safe HTTP request. Using the `requests` library here would have resulting in
212212
blocking code within the async event loop, which will block the entire async
213213
event loop. For more in-depth information about this issue, refer to the
214214
[Python asyncio documentation](https://docs.python.org/3/library/asyncio-dev.html#running-blocking-code).
215215

216-
The code below also implements the Activity Definition as a class, rather than a
216+
The following code also implements the Activity Definition as a class, rather than a
217217
function. The `aiohttp` library requires an established `Session` to perform the
218218
HTTP request. It would be inefficient to establish a `Session` every time an
219219
Activity is invoked, so instead this code accepts a `Session` object as an instance
@@ -255,9 +255,9 @@ class TranslateActivities:
255255
return translation
256256
```
257257

258-
### Running synchronous code from an asynchronous activity
258+
### How to run synchronous code from an asynchronous activity
259259

260-
If your activity is asynchronous and you don't want to change it to synchronous,
260+
If your Activity is asynchronous and you don't want to change it to synchronous,
261261
but you need to run blocking code inside it,
262262
then you can use python utility functions to run synchronous code
263263
in an asynchronous function:

0 commit comments

Comments
 (0)