首页 \ 问答 \ 是否有可能等待未声明为异步的IO操作?(Is it possible to await an IO operation that is not declared as async? If not, what should I do?)

是否有可能等待未声明为异步的IO操作?(Is it possible to await an IO operation that is not declared as async? If not, what should I do?)

我是C#中的异步编程新手,我仍然对一些事情感到困惑。 我已经阅读了.NET 4.5之后,APM和EAP不再被推荐用于新开发,因为TAP应该取代它们( 源代码 )。

我想我理解异步/等待如何工作,我可以使用它们来执行具有异步方法的IO操作。 例如,我可以编写一个异步方法,等待HttpWebClient的GetStringAsync结果,因为它被声明为异步方法。 那很棒。

我的问题是:如果我们在未声明为异步的方法中发生IO操作,该怎么办? 像这样:假设我有一个有方法的API

string GetResultFromWeb()

从Web查询某些内容。 我有很多不同的查询要做,我必须使用这种方法来做到这一点。 然后我需要处理每个查询结果。 我明白,如果这是一个异步方法,我会这样做:

Task<string> getResultTask = GetResultFromWeb(myUrl); 
// Do whatever I need to do that doesn't need the query result
string result = await getResultTask;
Process(result);

但由于不是,我不能等待它 - 它告诉我字符串不是等待的。 所以我的问题是:是否有任何方式异步执行这些IO操作,而不必为每个查询创建一个线程? 如果可以的话,我想创建尽可能少的线程,而不必阻塞任何线程。

我发现的一种方式是通过实施APM,遵循Jeffrey Richter的这篇文章 ,然后在我的Begin方法中,我调用ThreadPool.QueueWorkItem(GetResultFromWeb,asyncResult)。 喜欢这个:

public class A {
    private void DoQuery(Object ar){
        AsyncResult<string> asyncResult = (AsyncResult<string>) ar;
        string result = GetResultFromWeb();
        asyncResult.SetAsCompleted(result, false);
    }

    public IAsyncResult BeginQuery(AsyncCallback){
        AsyncResult<string> asyncResult = new AsyncResult<string>(callback, this);
        ThreadPool.QueueUserWorkItem(DoQuery, asyncResult);
        return asyncResult;
    }

    public string EndQuery(IAsyncResult ar){
        AsyncResult<string> asyncResult = (AsyncResult<string>)ar;
        return asyncResult.EndInvoke();
    }
}

然后,我使用AsyncEnumerator并开始(BeginQuery)几个查询,并在每个查询结束时处理结果(使用yield return / EndQuery)。 这似乎运作良好。 但是,在阅读了太多以至于APM已经过时之后,我想知道如何使用TAP来做到这一点。 另外,这种APM方法有什么问题吗?

谢谢!


I'm new to asynchronous programming in C# and I'm still confused about a few things. I've read that after .NET 4.5, the APM and EAP are no longer recommended for new development since the TAP is supposed to replace them (source).

I think I understood how async/await works and I'd be able to use them for performing IO operations that have async methods. For example, I could write an async method that awaits for an HttpWebClient's GetStringAsync result, since it's declared as an async method. That's great.

My question is: what if we have an IO operation that happens in a method that is not declared as async? Like this: suppose I have an API that has a method

string GetResultFromWeb()

which queries something from the Web. And I have lots of different queries to do and I must use this method to do so. And then I need to process each query result. I understand that I'd do this if that was an async method:

Task<string> getResultTask = GetResultFromWeb(myUrl); 
// Do whatever I need to do that doesn't need the query result
string result = await getResultTask;
Process(result);

But since it's not, I cannot await for it -- it tells me string is not awaitable. So my question is: is there any way of performing these IO operations asynchronously without having to create one thread for each query? If I could, I'd like to create as less threads as possible, without having to block any of the threads.

One way I found to do so was by implementing APM, following this article from Jeffrey Richter and then, in my Begin method, I call ThreadPool.QueueWorkItem(GetResultFromWeb, asyncResult). Like this:

public class A {
    private void DoQuery(Object ar){
        AsyncResult<string> asyncResult = (AsyncResult<string>) ar;
        string result = GetResultFromWeb();
        asyncResult.SetAsCompleted(result, false);
    }

    public IAsyncResult BeginQuery(AsyncCallback){
        AsyncResult<string> asyncResult = new AsyncResult<string>(callback, this);
        ThreadPool.QueueUserWorkItem(DoQuery, asyncResult);
        return asyncResult;
    }

    public string EndQuery(IAsyncResult ar){
        AsyncResult<string> asyncResult = (AsyncResult<string>)ar;
        return asyncResult.EndInvoke();
    }
}

Then I use an AsyncEnumerator and begin (BeginQuery) several queries and process the results as each one of them finishes (using yield return / EndQuery). This seems to work well. But after reading so much that APM is obsolete, I was wondering how could I do this using TAP. Also, is there any problem with this APM approach?

Thanks!


原文:https://stackoverflow.com/questions/27790468
更新时间:2023-02-08 07:02

最满意答案

编译器通常不知道A的构造函数是否有可观察的副作用,所以它总是会调用它。 它可能不会保持变量'a'。

因此,将调用构造函数,但结果可能不会分配给变量; 相反,如果没有其他任何东西引用它,A对象可能只是立即注册垃圾收集。 (在你的情况下,别的东西会引用它 - 即Container类 - 所以它不会被垃圾收集!)

在您的情况下,构造函数显然在任何情况下都有副作用(因此编译器优化掉构造函数调用将是一个重大错误)。

综上所述:

  • 构造函数将始终被调用。
  • 将结果赋值给局部变量可能无法完成,因为编译器知道它没有可观察的副作用。
  • 在你的代码中,其他东西保留了对构造对象的引用,所以它不会被GCed。

The compiler doesn't in general know if the constructor of A has observable side-effects, so it will always call it. It may not keep the variable 'a' around though.

So, the constructor will be called, but the result may not be assigned to the variable; instead the A object may just be immediately registered for garbage collection if nothing else references it. (In your case, something else DOES reference it - namely, the Container class - so it WON'T be garbage-collected!)

In your case, the constructor manifestly DOES have side-effects in any case (so it would be a major error for the compiler to optimise away the constructor call).

In summary:

  • The constructor will always be called.
  • The assignment of the result to the local variable may not be done because the compiler knows that it has no observable side-effects.
  • In your code, something else retains a reference to the constructed object, so it won't be GCed.

相关问答

更多

相关文章

更多

最新问答

更多
  • h2元素推动其他h2和div。(h2 element pushing other h2 and div down. two divs, two headers, and they're wrapped within a parent div)
  • 创建一个功能(Create a function)
  • 我投了份简历,是电脑编程方面的学徒,面试时说要培训三个月,前面
  • PDO语句不显示获取的结果(PDOstatement not displaying fetched results)
  • Qt冻结循环的原因?(Qt freezing cause of the loop?)
  • TableView重复youtube-api结果(TableView Repeating youtube-api result)
  • 如何使用自由职业者帐户登录我的php网站?(How can I login into my php website using freelancer account? [closed])
  • SQL Server 2014版本支持的最大数据库数(Maximum number of databases supported by SQL Server 2014 editions)
  • 我如何获得DynamicJasper 3.1.2(或更高版本)的Maven仓库?(How do I get the maven repository for DynamicJasper 3.1.2 (or higher)?)
  • 以编程方式创建UITableView(Creating a UITableView Programmatically)
  • 如何打破按钮上的生命周期循环(How to break do-while loop on button)
  • C#使用EF访问MVC上的部分类的自定义属性(C# access custom attributes of a partial class on MVC with EF)
  • 如何获得facebook app的publish_stream权限?(How to get publish_stream permissions for facebook app?)
  • 如何防止调用冗余函数的postgres视图(how to prevent postgres views calling redundant functions)
  • Sql Server在欧洲获取当前日期时间(Sql Server get current date time in Europe)
  • 设置kotlin扩展名(Setting a kotlin extension)
  • 如何并排放置两个元件?(How to position two elements side by side?)
  • 如何在vim中启用python3?(How to enable python3 in vim?)
  • 在MySQL和/或多列中使用多个表用于Rails应用程序(Using multiple tables in MySQL and/or multiple columns for a Rails application)
  • 如何隐藏谷歌地图上的登录按钮?(How to hide the Sign in button from Google maps?)
  • Mysql左连接旋转90°表(Mysql Left join rotate 90° table)
  • dedecms如何安装?
  • 在哪儿学计算机最好?
  • 学php哪个的书 最好,本人菜鸟
  • 触摸时不要突出显示表格视图行(Do not highlight table view row when touched)
  • 如何覆盖错误堆栈getter(How to override Error stack getter)
  • 带有ImageMagick和许多图像的GIF动画(GIF animation with ImageMagick and many images)
  • USSD INTERFACE - > java web应用程序通信(USSD INTERFACE -> java web app communication)
  • 电脑高中毕业学习去哪里培训
  • 正则表达式验证SMTP响应(Regex to validate SMTP Responses)