3

I try to verify my image URLs to see whether or not they are valid. I have so many of them that it take hours to complete this task. Therefore, I decided to do it asynchronously. I would like to know if there are any big differences or advantage of doing my code as below.

My main functions are:

Async Function testUrl_async(ByVal myImageurl As String) As Task(Of Boolean)

   myHttpResponse = Await myHttpClient.GetAsync(myImageurl)
    If myHttpResponse.IsSuccessStatusCode Then
        mySuccess = True
    Else
        mySuccess = False
    End If

    Return mySuccess
End Function

 Function testUrl(ByVal myImageurl As String) As  Boolean

   myHttpResponse = myHttpClient.GetAsync(myImageurl)
    If myHttpResponse.IsSuccessStatusCode Then
        mySuccess = True
    Else
        mySuccess = False
    End If

    Return mySuccess
End Function

1) using async await.

For Each myImage In myImages
    Dim result=await testUrl_async(myImageUrl).Result 
    'some code                  
Next

2) using parallel foreach

Parallel.ForEach(myImages, 
    Sub(myImage)
        testUrl(pictureComponent.websiteShop.hqpatronen, myImageUrl) 
        'some code
    End Sub)

3) using parallel foreach and asnyc/await

Parallel.ForEach(myImages, 
    Sub(myImage)
        await testUrl_async(pictureComponent.websiteShop.hqpatronen, myImageUrl) 
    'some code
    End Sub)

The third one could be the best solution, but it will not allow me to call Await/Async within the ForEach.

If I use the second one, the testurl function has the async http call, but not with Await, thereofore it crashes with the exception message:

[TaskCanceledException: A task was canceled.]

on the line that calls myHttpClient.GetAsync. I am guessing that it throws this exception because ForEach has ended and cancellation was requested but httpclient didn't finish its job yet. How can i handle this if this could be the best solution?

Alternatively any other solution which makes my job faster.

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
Emil
  • 6,411
  • 7
  • 62
  • 112
  • This may be a good task for TPL Dataflow, which provides rough Parallel.ForEach functionality with support for async. – Cory Nelson Jun 23 '15 at 15:30
  • is it new and only supported by 4.5 and higher versions? – Emil Jun 23 '15 at 15:36
  • 1
    @batmaci Just like `async/await`, yes – Panagiotis Kanavos Jun 23 '15 at 15:38
  • @PanagiotisKanavos async/await is supported in .NET 4.0. I don't believe TPL Dataflow is. – Cory Nelson Jun 23 '15 at 15:41
  • @CoryNelson only if you add the Microsoft.Build and Microsoft.Bcl.Async package that actually modify your build process to allow the keywords. It's a compatibility measure, not actual support. – Panagiotis Kanavos Jun 23 '15 at 15:43
  • 1
    @PanagiotisKanavos keywords are part of C#, not the framework. All the compatibility packages add is the framework bits necessary for the keywords to work. – Cory Nelson Jun 23 '15 at 15:46
  • 1
    @CoryNelson not exactly, since `async/await` doesn't require any extra IL. Even in C# 5, the compiler generates a state machine to handle awaiting. That's why `Microsoft.Build` is required - it actually changes the way a project is built. The compatibility packages do not modify the runtime itself nor do they add any new IL. – Panagiotis Kanavos Jun 23 '15 at 16:11

1 Answers1

11

You certainly don't want to use Parallel.ForEach. Parallel is for spreading CPU-bound algorithms over multiple cores, which would provide you no benefit (in your scenario, your algorithm is not CPU-bound).

What you actually want is concurrency, not parallelism. Asynchronous concurrency can be done using Task.WhenAll:

Dim tasks = myImages.Select(Function(x) testUrl_async(x))
Dim results = Await Task.WhenAll(tasks)
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Is there a big performance (speed) difference between my first approach with classic for each and sync-await? – Emil Jun 24 '15 at 08:31
  • I tested and it makes a big difference. thanks for your help :) – Emil Jun 24 '15 at 13:08
  • Can you kindly look into my other following post which is connected to this post indeed? I didnt want to ask further question but rather I created a new post. http://stackoverflow.com/questions/31027885/how-can-i-control-thread-count-when-i-use-task-whenall – Emil Jun 24 '15 at 13:41