使用FileStream的异步文件I/O阻塞了WPF的UI线程



我正试图从一个文件夹复制到另一个文件夹,并遵循msdn文章,我试图在我的WPF应用程序上实现asnyc调用。但我不确定我做错了什么,它阻塞UI线程,我不认为这第一个例子是asnyc。

这是我的代码

  Dim tasks = myImages.Select(Async Function(x)
                                                Dim result As Image
                                                Try
                                                    result = Await CopyImage(x, If(cts IsNot Nothing, cts.Token, Nothing))
                                                Catch ex2 As Exception
                                                End Try
                                                ProgressValue += 1
                                                CompletedText = ProgressValue.ToString() & " of " + MaxValue.ToString() & " images completed."
                                                Return result
                                            End Function)
                Dim results = Await Task.WhenAll(tasks)
  Public Async Function CopyImage(Image As Image, ct As CancellationToken) As Task(Of Image)
    If ct.IsCancellationRequested Then
        Return Nothing
    End If
    Await _mutex.WaitAsync()
    Dim SourceMainDirectory As String = "\ServerFolder1"
    Dim DestinationMainDirectory As String = = "\ServerFolder2"
    Dim Path = Image.Path.Replace("/", "")
    Dim Data As String() = Path.Split("")
    Dim Folder As String
    Dim ImageName As String
    If Data IsNot Nothing AndAlso Data.Length > 1 Then
        Folder = Data(0)
        ImageName = Data(1)      
    End If
    Dim ImgFullSource = SourceMainDirectory + Folder + "" + ImageName
    Dim ImgFullDest = DestinationMainDirectory + Folder + "" + ImageName
    Try
        Using SourceStream As FileStream = File.Open(ImgFullSource, FileMode.Open)
            Using DestinationStream As FileStream = File.Create(ImgFullDest)
                Await SourceStream.CopyToAsync(DestinationStream, 81920, ct)
                Return Image
            End Using
        End Using
    Catch ex As OperationCanceledException
        Return Nothing
    Catch ex As Exception
        Return Nothing
    Finally
        _mutex.Release()
    End Try
    Return Nothing
End Function
上面的

ProgressValue被引发以更新我的进度条值。这段代码工作得很好,没有阻塞UI线程,并完美地异步更新进度,如果我使用myHttpClient。GetAsync方法来验证web上相同的图像,例如

  Dim tasks = myImages.Select(Async Function(x)
                                                Dim result As Image
                                                Try
  result = Await  testUrl_async_cancel(x, If(cts IsNot Nothing, cts.Token, Nothing))
                                                Catch ex2 As Exception
                                                End Try
                                                ProgressValue += 1
                                                CompletedText = ProgressValue.ToString() & " of " + MaxValue.ToString() & " images completed."
                                                Return result
                                            End Function)
                Dim results = Await Task.WhenAll(tasks)
  Async Function testUrl_async_cancel( ByVal myImage As Image, ByVal ct As CancellationToken) As Task(Of AEL)
        If ct.IsCancellationRequested Then
            Return Nothing
        End If
        Await _mutex.WaitAsync()
        Dim myHttpClient As New HttpClient()
        Dim myHttpResponse As HttpResponseMessage
 myHttpClient.BaseAddress = New Uri(imageUrlD)

        Try
            myHttpResponse = Await myHttpClient.GetAsync(myImageUrl, ct)
        Catch ex As OperationCanceledException
            myHttpResponse = Nothing
        Catch ex As Exception
            myHttpResponse = Nothing
        Finally
            _mutex.Release()
        End Try
        If myHttpResponse IsNot Nothing AndAlso myHttpResponse.IsSuccessStatusCode Then
            Return Nothing
        Else
            Return myImage
        End If

    End Function

所以它应该与CopyImage函数有关,并分别使用源代码流阻塞UI线程,因为所有其他代码都是相同的。我怎样才能使这个代码异步,不会阻塞WPF上的UI线程?

这个行为是由于文件流中的一个奇怪现象。File.OpenFile.Create只能返回同步文件流。

要获得真正的异步文件流,您必须使用FileStream构造函数并将true传递给isAsync参数,或者在options参数中包含FileOptions.Asynchronous标志。必须使用isAsyncoptions调用构造函数重载,否则文件流将是同步的。

基于Stephen Cleary的回答。我改变了文件流读取和写入部分如下,它异步工作而不阻塞UI线程。我希望这有助于其他人寻找相同的解决方案。

最后一个参数True是Stephen提到的async参数

 Using SourceStream As FileStream = New FileStream(ImgFullSource, FileMode.Open, FileAccess.Read, FileShare.Read, 81920, True)
                Using DestinationStream As FileStream = New FileStream(ImgFullDest, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 81920, True)
                    Await SourceStream.CopyToAsync(DestinationStream, 81920, ct)
                    Return Image
                End Using
            End Using

最新更新