2017-05-24 24 views
-3

这是一个非常简单的例子,在互联网上可用异步/等待的概念,我不知道这个小逻辑可以如何使用开始/结束调用? 我需要做的就是使用两种方法准备一个复杂的逻辑(Async/Await和代表),所以我想从基本工作流程开始。如何使用Delegate/Callback编写相同的代码?

int countCharacters() 
    { 

     int count = 0; 
     using (StreamReader reader= new StreamReader("D:\\Data.txt")) 
     { 
      string content = reader.ReadToEnd(); 
      count = content.Length; 
      Thread.Sleep(5000); 
     } 
      return count; 
    } 
    private async void btnProcessFIle_Click(object sender, EventArgs e) 
    { 
     Task<int> task = new Task<int>(countCharacters); 
     task.Start(); 
     int count = await task; 
     lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString(); 


    } 
+3

我很好奇。为什么你想要完美的异步/等待代码并将其转换为使用Begin/End Invoke?开始/结束调用是做它的老方法。一旦你开始使用async/await,除了提交你需要做的家庭作业外,没有任何理由。 – bradgonesurfing

+3

你有什么尝试?你有什么特别的问题?从字面上看,使用_only_'Begin/EndInvoke()'是无法做到你想要的,因为它们没有包含'await'功能,它可以让你在完成时返回正确的线程。你需要添加一个对'Control.Invoke()'的调用来完成它,或者使用'Progress ',或者使用'SynchronizationContext',或者......正如你所看到的那样,你的问题太广泛了,除了不包含一个好的[mcve]帮助我们理解你实际需要帮助的是什么。 –

+0

@PeterDuniho我知道的是: 当我在async方法中调用这个KW的任何方法时,Await是一个暂停点,该函数将在后台运行。所有我想要使用痛苦的结构映射相同的逻辑Begin/EndInvoke。 由于Delegates是异步编程的传统方式,而Async/Await自4.5版以来一直与我们在一起。 –

回答

2

这是一个很简单的例子这是在异步/等待概念互联网上可用

这是一个非常糟糕的例子。

它使用任务构造函数和Start,这是一个明确的no-no(字面意思是没有有效的用例来做到这一点)。

它还在“异步示例”中的后台线程上同步使用文件系统。

如果你想的如何异步消费同步(例如,CPU绑定)代码的一个例子,那么这是一个更好的例子,几乎做同样的事情:

int countCharacters() 
{ 
    Thread.Sleep(5000); 
    return 13; 
} 

private async void btnProcessFIle_Click(object sender, EventArgs e) 
{ 
    var count = await Task.Run(() => countCharacters()); 
    lblCount.Text = "No. of characters in file=" + count; 
} 

注意,这是的示例如何异步调用UI线程的CPU绑定代码 - 它是而不是“异步概念”的示例。

我不知道如何使用开始/结束调用来实现这个小逻辑?

由于您的工作是在后台线程上同步工作,这实际上很简单; you can just use Delegate.BeginInvoke而不是创建自己的IAsyncResult(这是关于APM的非常困难的部分 - 如果您确实需要实现它,请参阅2007-03 issue of MSDN Magazine中的“实现CLR异步编程模型”)。

但因为你可以只使用Delegate.BeginInvoke,这是非常简单的:

private void btnProcessFIle_Click(object sender, EventArgs e) 
{ 
    var ui = SynchronizationContext.Current; 
    Func<int> d = countCharacters; 
    d.BeginInvoke(CountCharactersCallback, ui); 
} 

private void CountCharactersCallback(IAsyncResult ar) 
{ 
    var d = (Func<int>) ((AsyncResult) ar).AsyncDelegate; 
    var ui = (SynchronizationContext) ar.AsyncState; 
    try 
    { 
    var count = d.EndInvoke(ar); 
    ui.Post(CountCharactersComplete, count); 
    } 
    catch (Exception ex) 
    { 
    var edi = ExceptionDispatchInfo.Capture(ex); 
    ui.Post(CountCharactersError, state); 
    } 
} 

private void CountCharactersComplete(object state) 
{ 
    var count = (int) state; 
    lblCount.Text = "No. of characters in file=" + count; 
} 

private void CountCharactersError(object state) 
{ 
    var edi = (ExceptionDispatchInfo)state; 
    edi.Throw(); 
} 

注:

  • CountCharactersCallback是 “裸露的回调”。从CountCharactersCallback传播的任何例外都表示灾难性错误。
  • 尤其要注意的是,不要允许EndInvoke的例外传播出BeginInvoke回调。这是一个常见的错误。
  • 我使用SynchronizationContext来同步回UI线程。这与await的行为相同。
  • 我使用ExceptionDispatchInfo跨线程保留异常堆栈跟踪(不需要包装异常)。
  • CountCharactersError只是直接在消息循环中引发异常。这与async void的行为相同。
+0

精彩的答案,我很高兴你考虑我的问题 - :)。 我想问2件事,你提供的链接是坏的或者不可下载,那么请你解释一下。 **请注意,这是一个如何异步调用UI线程的CPU绑定代码的示例 - 它不是“异步概念”的示例。**或者您是否可以提供任何链接以使此语句对我来说可以理解。 –

+0

1)您必须解除阻止文件(在属性下单击鼠标右键)。 2)最初的例子[使用'Task.Run'作为错误的东西](https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html)。 –

0

功能的BeginInvoke是获得非UI线程里面的UI元素,所以你需要改变你的代码是这样的:

private async void btnProcessFIle_Click(object sender, EventArgs e) 
{ 
    var task = Task.Run(() => { 
    var count = countCharacters(); 
    lblCount.BeginInvoke((Action) (() => 
     { 
     lblCount.Text = "No. of characters in file=" +Environment.NewLine+ 
      count.ToString(); 
     })); 
    }); 

    await task; 

} 
+0

我既不想使用* Task *也不想异步或等待。我想用这个Delegate,CallBack,BeginInvoke和EndInvoke来实现。我真的很问吗? –

+1

@Eqra - Task和async/await是为了实现TAP而创建的 - 如果你只想使用多线程 - 没有问题(但是为什么? - 在这种情况下,你的btnProcessFIle_Click()会在任务结束时被“冻结”) - 例如你可以在msdn中找到,在“Task Class”中定义https://msdn.microsoft.com/en-us/library/system.threading.tasks.task%28v=vs.110%29.aspx?f=255&MSPPError=- 2147217396 – Alexander

+0

这不是OP要求的。问题是*不*如何更新用户界面。这是如何使用APM模型,即BeginReadToEnd等 –

-1

代码,而异步/ AWAIT。你并不需要使用的BeginInvoke,因为你可以用TaskScheduler.FromCurrentSynchronizationContext()

int countCharacters() 
    { 

     int count = 0; 
     using (StreamReader reader= new StreamReader("D:\\Data.txt")) 
     { 
      string content = reader.ReadToEnd(); 
      count = content.Length; 
      Thread.Sleep(5000); 
     } 
      return count; 
    } 


    private void btnProcessFIle_Click(object sender, EventArgs e) 
    { 
     Task<int> task = new Task<int>(countCharacters); 
     task.Start(); 
     var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
     task.ContinueWith(count =>{ 

       lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString(); 
     }, uiScheduler); 
    } 

捕捉上下文如果你真的想使用的BeginInvoke我想你可以写

private void btnProcessFIle_Click(object sender, EventArgs e) 
    { 
     Task<int> task = new Task<int>(countCharacters); 
     task.Start(); 
     var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
     task.ContinueWith(count =>{ 
       lblCount.BeginInvoke(()=>{ 
        lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString(); 
       }); 

     }); 
    } 
相关问题