首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果我知道某个时间点有I/O,那么我是否应该调用一个brownfield API异步?

如果我知道某个时间点有I/O,那么我是否应该调用一个brownfield API异步?
EN

Stack Overflow用户
提问于 2017-07-11 17:17:46
回答 1查看 85关注 0票数 2

我正在开发一个使用我们编写的旧API的项目(即不是第三方,但目前还没有开发)。旧API执行非托管I/O操作:它通过运行时可调用包装器(RCWs)使用COM DLL连接到中间层服务器。这个新项目本身将是一个新应用程序的API,正如我所说的那样,它使用了旧的API;但是,我想在适当的地方公开异步方法,因为我还不确定我将如何使用新的API。例如,如果我在web应用程序中使用它,我希望确保我不会不必要地阻塞线程,等待COM DLL内部正在发生的I/O操作。

下面是我的新应用程序的样子:

代码语言:javascript
复制
------------------------------
|  CLIENT (WIN32, WEB, ETC.)  |
-------------------------------
------------------------------
|         NEW API             |
-------------------------------
------------------------------
|         OLD API             |
-------------------------------
------------------------------
|         COM DLL             |
-------------------------------

这确实简化了,使它看起来像是新API的唯一目的是包装旧API,但是新API是一个单独的应用程序,它有自己的业务逻辑,并且使用旧API来完成一定的操作。

我已经阅读了很多关于异步/等待的适当使用的文章,尤其是在brownfield应用程序中;例如,Stephen的MSDN杂志关于这一主题的文章非常有用。不过,我在为我的案子而挣扎。如果我没有直接使用真正的异步I/O方法,例如HttpClient.GetAsync,但我知道(或相当肯定) COM在没有线程的情况下执行I/O,有还是没有线吗?换句话说,线程一旦到达通过旧的同步API调用的COM DLL内部的I/O操作,就会被放弃吗?

这是一些示例代码。这是旧的API:

代码语言:javascript
复制
public class OldApi
{
    public bool TryCheckOutDocument(int docNum, out Document document)
    {
        // use COM dll to "check out" the doc.
    }

    public bool TryCheckInDocument(Document document)
    {
        // " " "check in" the doc.
    }
}

public class Document
{
    public int DocNum { get; }
    public object OtherData { get; set; }
}

下面是新的API:

代码语言:javascript
复制
public class NewApi
{
    public async Task ConvertDocsAsync(IEnumerable<int> docNums)
    {
        var oldApi = new OldApi();

        Parallel.ForEach(docNums, async (docNum) =>
        {
            Document doc = null;

            if (await Task.Run(() => !oldApi.TryCheckOutDocument(docNum, out doc)))
                throw new Exception($"blah blah: {docNum}");

            doc.OtherData = "this represents the conversion";

            if (await Task.Run(() => !oldApi.TryCheckInDocument(doc)))
                throw new Exception($"blah blah: {docNum}");
        });
    }
}

我使用Task.Run调用旧API中的同步方法。当他们击中I/O操作时,线程会被放弃吗?如果没有,是否有更好的方法使用异步/等待以确保异步的最有效使用?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-11 18:19:01

我使用Task.Run调用旧API中的同步方法。当他们击中I/O操作时,线程会被放弃吗?如果没有,是否有更好的方法使用异步/等待以确保异步的最有效使用?

不,因为旧的API是同步的,所以您不能“强制”它是异步的。

如果我没有直接使用真正的异步I/O方法.但我知道(或相当肯定) COM DLL在没有线程的情况下执行I/O操作,还没有线程吗?换句话说,线程一旦到达通过旧的同步API调用的COM DLL内部的I/O操作,就会被放弃吗?

所有I/O本质上都是异步的,但在这种情况下,第一个同步调用是阻塞该I/O上的线程,所以即使COM DLL是异步的,旧API也只是公开同步API --旧API将阻塞线程。

此外,将asyncParallel结合使用肯定会带来痛苦的体验。

您现在最好的选择是保持同步:

代码语言:javascript
复制
Parallel.ForEach(docNums, docNum =>
{
  Document doc = null;

  if (!oldApi.TryCheckOutDocument(docNum, out doc))
    throw new Exception($"blah blah: {docNum}");

  doc.OtherData = "this represents the conversion";

  if (!oldApi.TryCheckInDocument(doc))
    throw new Exception($"blah blah: {docNum}");
});

在用异步方法更新旧API之前,此时您可以执行异步并发:

代码语言:javascript
复制
var tasks = docNums.Select(async docNum =>
{
  Document doc = await oldApi.CheckOutDocumentAsync(docNum);
  doc.OtherData = "this represents the conversion";
  await oldApi.CheckInDocumentAsync(doc);
});
await Task.WhenAll(tasks);
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45040896

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档