Skip to content

Commit

Permalink
Merge branch 'main' into konstantin/links_checker_action
Browse files Browse the repository at this point in the history
  • Loading branch information
kochaika committed Dec 6, 2023
2 parents 7b48ed8 + 5a5fa85 commit fd0ab6e
Show file tree
Hide file tree
Showing 62 changed files with 264 additions and 62 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/Before you start/*/build
/Coroutines/*/build/
/.coursecreator/
/.gradle/
Expand Down
3 changes: 3 additions & 0 deletions Before you start/Course structure/src/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fun main() {
// Write your solution here
}
4 changes: 4 additions & 0 deletions Before you start/Course structure/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: theory
files:
- name: src/Main.kt
visible: true
1 change: 1 addition & 0 deletions Before you start/Course structure/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id: 1972445880
25 changes: 25 additions & 0 deletions Before you start/Course structure/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## Course structure
The course consists of 14 tasks in each of which you will improve the result of the previous task using new knowledge. Some tasks will give you theoretical knowledge

<ul>
<li>Task 1: Run the code</li>
<li>Task 2: Blocking requests</li>
<ul>
<li style="margin-left:-2em;">Task 3: Aggregation</li>
</ul>
<li>Task 4: Callbacks</li>
<ul>
<li style="margin-left:-2em;">Task 5: Retrofit callback API</li>
</ul>
<li>Task 6: Suspending functions</li>
<li>Task 7: Coroutines</li>
<li>Task 8: Concurrency</li>
<li>Task 9: Structured concurrency</li>
<ul>
<li style="margin-left:-2em;">Task 10: Canceling</li>
<li style="margin-left:-2em;">Task 11: Outer scope</li>
</ul>
<li>Task 12: Showing progress</li>
<li>Task 13: Channels</li>
<li>Task 14: Testing</li>
</ul>
3 changes: 3 additions & 0 deletions Before you start/Getting to know you/src/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fun main() {
// Write your solution here
}
4 changes: 4 additions & 0 deletions Before you start/Getting to know you/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: theory
files:
- name: src/Main.kt
visible: true
1 change: 1 addition & 0 deletions Before you start/Getting to know you/task-remote-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id: 1043970691
5 changes: 5 additions & 0 deletions Before you start/Getting to know you/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Getting to know you

Thank you for taking our Coroutines and channels course!
We would be happy to get to know you a bit better, so we’re asking you to fill
in [this brief form](https://surveys.jetbrains.com/s3/course-introduction-coroutines-channels).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions Before you start/GitHub developer token/task-info.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
type: theory
files:
- name: src/Main.kt
visible: true
- name: src/Main.kt
visible: true
- name: images/generating-token.png
visible: false
- name: images/generating-token_dark.png
visible: false
9 changes: 6 additions & 3 deletions Before you start/GitHub developer token/task.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
You'll be using the GitHub API in your project. To get access, provide your GitHub account name and either a password or a token. If you have two-factor authentication enabled, a token will be enough.
In this course, you'll learn how to use coroutines in the example of a program that loads the contributors for all of the repositories under the given GitHub organization.

So, you'll be using the GitHub API in your project. To get access, you'll need to provide your GitHub account name and either a password or a token. If you have two-factor authentication enabled, a token will be enough.

Generate a new GitHub token to use the GitHub API with [your account](https://github.com/settings/tokens/new):

1. Specify the name of your token, for example, `coroutines-tutorial`:

![Generating token interface](images/generating-token.png)
2. Do not select any scopes. **Click Generate** token at the bottom of the page.
3. Copy the generated token.
3. Copy the generated token to safe place. You won't be able to see him again in the future. If you lose it, you will need to create a new one.

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#generate-a-github-developer-token)
4 changes: 3 additions & 1 deletion Before you start/lesson-info.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
content:
- GitHub developer token
- Course structure
- GitHub developer token
- Getting to know you
4 changes: 3 additions & 1 deletion Coroutines/Aggregation/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ The corresponding test file [test/tasks/AggregationKtTest.kt](course://Coroutine

After implementing this task, the resulting list for the "kotlin" organization should be similar to the following:

![The list for the "kotlin" organization](images/aggregate.png)
![The list for the "kotlin" organization](images/aggregate.png)

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#task-1)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions Coroutines/Blocking requests/task-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ files:
visible: false
- name: runConfigurations/MainKt-Blocking_requests.run.xml
visible: false
- name: images/blocking_dark.png
visible: false
3 changes: 2 additions & 1 deletion Coroutines/Blocking requests/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ This API is used by the `loadContributorsBlocking()` function to fetch the list
name in square brackets. You can see from which thread the loading request is called.
* The final item on each line is the actual message: how many repositories or contributors were loaded.


This log output demonstrates that all of the results were logged from the main thread. When you run the code with a _BLOCKING_
option, the window freezes and doesn't react to input until the loading is finished. All of the requests are executed from
the same thread as the one called `loadContributorsBlocking()` is from, which is the main UI thread (in Swing, it's an AWT
Expand All @@ -49,4 +50,4 @@ This API is used by the `loadContributorsBlocking()` function to fetch the list
* Since `loadContributorsBlocking()` is also called from the UI thread, the UI thread becomes blocked and the UI is
frozen.


For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#blocking-requests)
Binary file added Coroutines/Callbacks/images/background_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions Coroutines/Callbacks/task-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ files:
visible: false
- name: test/tasks/Request2BackgroundKtTest.kt
visible: true
- name: images/background_dark.png
visible: false
6 changes: 4 additions & 2 deletions Coroutines/Callbacks/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ which uses callbacks instead of blocking calls.
However, if you try to load the contributors via the `BACKGROUND` option, you can see that the list is updated but
nothing changes.

### Task
## Task

Fix the `loadContributorsBackground()` function in [src/tasks/Request2Background.kt](course://Coroutines/Callbacks/src/tasks/Request2Background.kt) so that the resulting list is shown
in the UI.
in the UI.

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#callbacks)
21 changes: 11 additions & 10 deletions Coroutines/Canceling/task.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
Create two versions of the function that loads the list of contributors. Compare how both versions behave when you try to
cancel the parent coroutine. The first version will use `coroutineScope` to start all of the child coroutines,
whereas the second will use `GlobalScope`.
Look at two versions of the function that loads the list of contributors. Compare how both versions behave when you try to
cancel the parent coroutine. The first version is using `coroutineScope` to start all of the child coroutines,
whereas the second is using `GlobalScope`.

1. In [Request5Concurrent.kt](course://Coroutines/Canceling/src/tasks/Request5Concurrent.kt), add a 3-second delay to the `loadContributorsConcurrent()` function.
1. In [src/tasks/Request5Concurrent.kt](course://Coroutines/Canceling/src/tasks/Request5Concurrent.kt), uncomment 3-second delay in the `loadContributorsConcurrent()` function.

The delay affects all of the coroutines that send requests, so that there's enough time to cancel the loading
after the coroutines are started but before the requests are sent.

2. Create the second version of the loading function: copy the implementation of `loadContributorsConcurrent()` to
`loadContributorsNotCancellable()` in [Request5NotCancellable.kt](course://Coroutines/Canceling/src/tasks/Request5NotCancellable.kt) and then remove the creation of a new `coroutineScope`.
3. The `async` calls now fail to resolve, so start them by using `GlobalScope.async`:
2. Look at the second version of the loading function: `loadContributorsNotCancellable()` in [src/tasks/Request5NotCancellable.kt](course://Coroutines/Canceling/src/tasks/Request5NotCancellable.kt)
3. It is using `GlobalScope.async`:

```kotlin
suspend fun loadContributorsNotCancellable(
Expand All @@ -30,7 +29,7 @@ whereas the second will use `GlobalScope`.
* All of the "contributors" coroutines are started inside the `GlobalScope`, not as children of the coroutine scope
(line `#2`).

4. Run the program and choose the _CONCURRENT_ option to load the contributors.
4. Run the program and choose the `CONCURRENT` option to load the contributors.
5. Wait until all of the "contributors" coroutines are started, and then click _Cancel_. The log shows no new results,
which means that all of the requests were indeed canceled:

Expand Down Expand Up @@ -59,7 +58,7 @@ whereas the second will use `GlobalScope`.

In this case, no coroutines are canceled, and all the requests are still sent.

7. Check how the cancellation is triggered in the [Contributors.kt](course://Coroutines/Canceling/src/contributors/Contributors.kt). When the _Cancel_ button is clicked,
7. Check how the cancellation is triggered in the [src/contributors/Contributors.kt](course://Coroutines/Canceling/src/contributors/Contributors.kt). When the _Cancel_ button is clicked,
the main "loading" coroutine is explicitly canceled and the child coroutines are canceled automatically.

The `launch` function returns an instance of `Job`. `Job` stores a reference to the "loading coroutine", which loads
Expand All @@ -78,4 +77,6 @@ job.setUpCancellation()
* Then you could add a listener to the _Cancel_ button so that when it's clicked, the `loadingJob` is canceled (line `#3`).
With structured concurrency, you only need to cancel the parent coroutine and this automatically propagates cancellation
to all of the child coroutines.
to all of the child coroutines.
For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#canceling-the-loading-of-contributors)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Coroutines/Channels/images/progress_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions Coroutines/Channels/task-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,19 @@ files:
visible: false
- name: test/tasks/Request2BackgroundKtTest.kt
visible: true
- name: images/conflated-channel_dark.gif
visible: false
- name: images/using-channel-many-coroutines_dark.png
visible: false
- name: images/progress_dark.png
visible: false
- name: images/progress-and-concurrency_dark.png
visible: false
- name: images/using-channel_dark.png
visible: false
- name: images/unlimited-channel_dark.png
visible: false
- name: images/buffered-channel_dark.png
visible: false
- name: images/rendezvous-channel_dark.png
visible: false
17 changes: 9 additions & 8 deletions Coroutines/Channels/task.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#### Consecutive vs concurrent
## Consecutive vs concurrent

An `updateResults()` callback is called after each request is completed:

Expand Down Expand Up @@ -103,23 +103,22 @@ val unlimitedChannel = Channel<String>(UNLIMITED)

By default, a "Rendezvous" channel is created.

In the following task, you'll create a "Rendezvous" channel, two producer coroutines, and a consumer coroutine. Check out [ChannelsSample.kt](course://Coroutines/Channels/src/samples/ChannelsSample.kt)
In the following task, you'll create a "Rendezvous" channel, two producer coroutines, and a consumer coroutine. Check out [src/samples/ChannelsSample.kt](course://Coroutines/Channels/src/samples/ChannelsSample.kt)

<div class="hint">

> Watch [this video](https://www.youtube.com/watch?v=HpWQUoVURWQ) for a better understanding of channels.
>
> Watch <a href="https://www.youtube.com/watch?v=HpWQUoVURWQ" target="_blank">this video</a> for a better understanding of channels.
</div>


### Task
## Task

In [src/tasks/Request7Channels.kt](course://Coroutines/Channels/src/tasks/Request7Channels.kt), implement the function `loadContributorsChannels()` that requests all of the GitHub
contributors concurrently and shows intermediate progress at the same time.

Use the previous functions, `loadContributorsConcurrent()` from [Request5Concurrent.kt](course://Coroutines/Channels/src/tasks/Request5Concurrent.kt)
and `loadContributorsProgress()` from [Request6Progress.kt](course://Coroutines/Channels/src/tasks/Request6Progress.kt).
Use the previous functions, `loadContributorsConcurrent()` from [src/tasks/Request5Concurrent.kt](course://Coroutines/Channels/src/tasks/Request5Concurrent.kt)
and `loadContributorsProgress()` from [src/tasks/Request6Progress.kt](course://Coroutines/Channels/src/tasks/Request6Progress.kt).


<div class="hint">
Expand Down Expand Up @@ -148,4 +147,6 @@ repeat(repos.size) {
```

Since the `receive()` calls are sequential, no additional synchronization is needed.
</div>
</div>

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#channels)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion Coroutines/Concurrency/task-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ files:
- name: test/tasks/Request5ConcurrentKtTest.kt
visible: true
- name: images/concurrency.png
visible: true
visible: false
- name: test/tasks/Request2BackgroundKtTest.kt
visible: true
- name: images/concurrency_dark.png
visible: false
14 changes: 8 additions & 6 deletions Coroutines/Concurrency/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ by calling `Job.join()`.
depending on what the lambda returns (the last expression inside the lambda is the result).

To get the result of a coroutine, you can call `await()` on the `Deferred` instance. While waiting for the result,
the coroutine that this `await()` is called from is suspended. See the example in the [ConcurrencySample.kt](course://Coroutines/Concurrency/src/samples/ConcurrencySample.kt).
the coroutine that this `await()` is called from is suspended. See the example in the [src/samples/ConcurrencySample.kt](course://Coroutines/Concurrency/src/samples/ConcurrencySample.kt).

`runBlocking` is used as a bridge between regular and suspending functions, or between the blocking and non-blocking worlds. It works
as an adaptor for starting the top-level main coroutine. It is intended primarily to be used in `main()` functions and
tests.

> Watch [this video](https://www.youtube.com/watch?v=zEZc5AmHQhk) for a better understanding of coroutines.
> Watch <a href="https://www.youtube.com/watch?v=zEZc5AmHQhk" target="_blank">this video</a> for a better understanding of coroutines.
If there is a list of deferred objects, you can call `awaitAll()` to await the results of all of them. See the example in the [ConcurrencySample.kt](course://Coroutines/Concurrency/src/samples/ConcurrencySample.kt)
If there is a list of deferred objects, you can call `awaitAll()` to await the results of all of them. See the example in the [src/samples/ConcurrencySample.kt](course://Coroutines/Concurrency/src/samples/ConcurrencySample.kt)

When each "contributors" request is started in a new coroutine, all of the requests are started asynchronously. A new request
can be sent before the result for the previous one is received:
Expand All @@ -34,9 +34,9 @@ can be sent before the result for the previous one is received:
The total loading time is approximately the same as in the _CALLBACKS_ version, but it doesn't need any callbacks.
What's more, `async` explicitly emphasizes which parts run concurrently in the code.

### Task 5
## Task

In the [Request5Concurrent.kt](course://Coroutines/Concurrency/src/tasks/Request5Concurrent.kt) file, implement a `loadContributorsConcurrent()` function by using the
In the [src/tasks/Request5Concurrent.kt](course://Coroutines/Concurrency/src/tasks/Request5Concurrent.kt) file, implement a `loadContributorsConcurrent()` function by using the
previous `loadContributorsSuspend()` function.

<div class="hint">
Expand All @@ -62,4 +62,6 @@ val deferreds: List<Deferred<List<User>>> = repos.map { repo ->
}
deferreds.awaitAll() // List<List<User>>
```
</div>
</div>

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#concurrency)
Binary file modified Coroutines/Coroutines/images/run-configuration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions Coroutines/Coroutines/task-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,9 @@ files:
visible: false
- name: runConfigurations/MainKt-Coroutines.run.xml
visible: false
- name: images/suspension-process_dark.gif
visible: false
- name: images/suspend-requests_dark.png
visible: false
- name: images/run-configuration_dark.png
visible: false
4 changes: 3 additions & 1 deletion Coroutines/Coroutines/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ despite all the requests taking place on the main UI thread:
11252 [AWT-EventQueue-0 @coroutine#1] INFO Contributors - kotlin-coroutines-workshop: loaded 1 contributors
```

2. The log can show you which coroutine the corresponding code is running on. To enable it, open **Run | Edit configurations**
2. The log can show you which coroutine the corresponding code is running on. For the configuration invoked by clicking `Run` button this is already set up. To enable it in your own configurations, open **Run | Edit configurations**
and add the `-Dkotlinx.coroutines.debug` VM option:


Expand All @@ -73,3 +73,5 @@ written sequentially. The new request is sent only when the previous result is r

Suspending functions treat the thread fairly and don't block it for "waiting". However, this doesn't yet bring any concurrency
into the picture.

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#coroutines)
1 change: 1 addition & 0 deletions Coroutines/Outer scope/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ top-level coroutine. All the nested coroutines then inherit the context and modi
> you need to run the code on a different thread.
</div>
For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#using-the-outer-scope-s-context)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions Coroutines/Retrofit callback API/task-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ files:
visible: false
- name: test/tasks/Request2BackgroundKtTest.kt
visible: true
- name: images/callbacks_dark.png
visible: false
6 changes: 4 additions & 2 deletions Coroutines/Retrofit callback API/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Open [src/tasks/Request3Callbacks.kt](course://Coroutines/Retrofit callback API/
However, the provided solution doesn't work. If you run the program and load contributors by choosing the _CALLBACKS_
option, you'll see that nothing is shown. However, the tests that immediately return the result pass.

### Task
## Task

Rewrite the code in the [src/tasks/Request3Callbacks.kt](course://Coroutines/Retrofit callback API/src/tasks/Request3Callbacks.kt) file so that the loaded list of contributors is shown.
Rewrite the code in the [src/tasks/Request3Callbacks.kt](course://Coroutines/Retrofit callback API/src/tasks/Request3Callbacks.kt) file so that the loaded list of contributors is shown.

For a more detailed description, you can look at [this article](https://kotlinlang.org/docs/coroutines-and-channels.html#use-the-retrofit-callback-api)
2 changes: 1 addition & 1 deletion Coroutines/Run the code/task.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The program loads the contributors for all of the repositories under the given organization (named “kotlin” by default). Later you'll add logic to sort the users by the number of their contributions.

Open the [src/contributors/main.kt](course://Coroutines/Run the code/src/contributors/main.kt) file and run the `main()` function. You'll see the following window:
Open the [src/contributors/main.kt](course://Coroutines/Run the code/src/contributors/main.kt) file and run the `main()` function or just use the "Run" button below. You'll see the following window:

![First window](images/initial-window.png)

Expand Down
Loading

0 comments on commit fd0ab6e

Please sign in to comment.