【问题标题】:Asynchronous File I/O using FileStream is blocking UI thread on WPF使用 FileStream 的异步文件 I/O 阻塞了 WPF 上的 UI 线程
【发布时间】:2017-02-21 09:22:52
【问题描述】:

我正在尝试从一个文件夹复制到另一个文件夹并遵循 msdn article 我尝试在我的 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 = "\\Server\Folder1"
    Dim DestinationMainDirectory As String = = "\\Server\Folder2"

    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 被提出来更新我的progressbar 值。此代码在不阻塞 UI 线程的情况下工作正常,并且完美地异​​步更新进度如果我使用 myHttpClient.GetAsync 方法来验证网络上的相同图像,例如

  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 线程?

【问题讨论】:

    标签: wpf vb.net async-await


    【解决方案1】:

    此行为是由于文件流中的异常所致。 File.Open 和 File.Create 只能返回同步文件流。

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

    【讨论】:

    • 太棒了。它就像一个魅力。我接受您的回答,并将我的代码更改添加为下面的答案。谢谢。
    【解决方案2】:

    基于 Stephen Cleary 的回答。我将文件流读写部分更改如下,它异步工作而不会阻塞 UI 线程。我希望这可以帮助其他寻找相同解决方案的人。

    最后一个参数True是斯蒂芬提到的异步参数。

     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
    

    【讨论】:

      猜你喜欢
      • 2018-04-06
      • 1970-01-01
      • 2014-01-23
      • 1970-01-01
      • 2017-07-07
      • 1970-01-01
      • 2019-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多