https://kotlinlang.org logo
Title
h

hooliooo

10/26/2020, 3:21 PM
Hello, I’m currently trying to determine if my async calls are running concurrently or sequentially. I currently have this code:
val (firstImageBlobName, firstImageThumbnailBlobName, secondImageBlobName, secondImageThumbnailBlobName) = try {
    coroutineScope {
        AsyncImageUploads(
            firstImageBlobName = async {
                fileServiceInterface.uploadImage(
                    ...
                )
            },
            firstImageThumbnailBlobName = async {
                fileServiceInterface.uploadImage(
                    ...
                )
            },
            secondImageBlobName = async {
                fileServiceInterface.uploadImage(
                    ...
                )
            },
            secondImageThumbnailBlobName = async {
                fileServiceInterface.uploadImage(
                    ...
                )
            }
        )
    }
} catch (e: Exception) {
    ....
}

repository.save(
    model.copy(
        firstImage = firstImageRepository.save(
            FirstImage(
                imageURL = firstImageBlobName.await(),
                thumbnailURL = firstImageThumbnailBlobName.await(),
                model = model
            )
        ),
        secondImage = secondImageRepository.save(
            SecondImage(
                imageUrl = secondImageBlobName.await(),
                thumbnailUrl = secondImageThumbnailBlobName.await(),
                model = model
            )
        )
    )
)
The issue is the upload takes around 40 seconds to finish 🤔 so I’m wondering if the async calls are happening concurrently
l

louiscad

10/26/2020, 4:07 PM
It all depends on how
AsyncImageUploads
is implemented.
h

hooliooo

10/27/2020, 7:18 AM
It’s just a data class that holds four Deferred<String> since there’s no generic 4 property Tuple
m

marstran

10/27/2020, 7:58 AM
What kind of dispatcher are you running it in?
Also, is the
uploadImage
function suspending or blocking?
j

Jonas Bark

10/27/2020, 8:17 AM
the uploadImage is suspending, but does heavy operations using ImageIO (resize etc) but does that matter when using async?
h

hooliooo

10/27/2020, 8:19 AM
@marstran I’m assuming it’s the Default one because it’s not explicitly defined. Should it be defined as the IO one? I’m using Azure Blob storage for uploading and using the asyncClient. The function
uploadImage
is suspending. Under the hood the uploadImage function has image resizing with ImageIO and then uses awaitFirst/awaitFirstOrNull which according to the docs is non blocking.
j

Jonas Bark

10/27/2020, 8:44 AM
@hooliooo the uploading to Azure Blob storage is non blocking - the ImageIO does block
👍 1
h

hooliooo

10/27/2020, 11:24 AM
Did some print statements
// coroutineScope
Current Thread for first-image-for-1: main @coroutine#5
4684 millis elapsed resizeImage first-image-for-1
Current Thread for first-image-thumb-for-1: main @coroutine#6
4828 millis elapsed resizeImage first-image-thumb-for-1
Current Thread for second-image-for-1: main @coroutine#7
4977 millis elapsed resizeImage second-image-for-1
Current Thread for second-image-thumb-for-1: main @coroutine#8
5033 millis elapsed resizeImage second-image-thumb-for-1
5075 millis elapsed uploadFile first-image-thumb-for-1
5080 millis elapsed uploadFile first-image-for-1
5086 millis elapsed uploadFile second-image-for-1
5097 millis elapsed uploadFile second-image-thumb-for-1

// withContext(<http://Dispatchers.IO|Dispatchers.IO>)
Current Thread for first-image-for-1: DefaultDispatcher-worker-3 @coroutine#5
Current Thread for second-image-for-1: DefaultDispatcher-worker-5 @coroutine#7
Current Thread for first-image-thumb-for-1: DefaultDispatcher-worker-2 @coroutine#6
Current Thread for second-image-thumb-for-1: DefaultDispatcher-worker-4 @coroutine#8
4775 millis elapsed resizeImage first-image-for-1
4788 millis elapsed resizeImage second-image-thumb-for-1
4802 millis elapsed resizeImage first-image-thumb-for-1
4837 millis elapsed resizeImage second-image-for-1
5060 millis elapsed uploadFile first-image-thumb-for-1
5068 millis elapsed uploadFile second-image-for-1
5074 millis elapsed uploadFile first-image-for-1
5084 millis elapsed uploadFile second-image-thumb-for-1
Seems like coroutineScope will execute the next coroutine after the resizeImage (blocking call) while withContext(Dispatchers.IO), the coroutines are executed around the same time Ignore the actual millis. I used an external start time (outside the function scope so the coroutines have the same start time reference) The order in the uploadImage method is: Current Thread for… resizeImage uploadFile
m

marstran

10/27/2020, 2:09 PM
Seems like all coroutines ran in the same
main
thread before you changed the dispatcher.