Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果我知道棕地API在某个点进行I/O操作,我是否应该对棕地API进行异步调用?_C#_.net_Multithreading_Asynchronous_Async Await - Fatal编程技术网

C# 如果我知道棕地API在某个点进行I/O操作,我是否应该对棕地API进行异步调用?

C# 如果我知道棕地API在某个点进行I/O操作,我是否应该对棕地API进行异步调用?,c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,我正在从事一个利用我们编写的旧API的项目(即不是第三方的,但目前还没有开发中)。旧API执行非托管I/O操作:它通过运行时可调用包装器(RCW)使用COM DLL连接到中间层服务器。这个新项目本身将是一个新应用程序的API,正如我所说的,它利用了旧的API;但是,我希望在适当的地方公开异步方法,因为我还不确定如何使用新的API。例如,如果我在web应用程序中使用它,我希望确保我没有不必要地阻塞线程,以等待在COM DLL深处发生的I/O操作 以下是我的新应用程序的外观: -----------

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

以下是我的新应用程序的外观:

------------------------------
|  CLIENT (WIN32, WEB, ETC.)  |
-------------------------------
------------------------------
|         NEW API             |
-------------------------------
------------------------------
|         OLD API             |
-------------------------------
------------------------------
|         COM DLL             |
-------------------------------
这是非常简化的,并且看起来新API的唯一用途是包装旧API,但是新API是一个单独的应用程序,它有自己的业务逻辑,并且在一定比例的操作中使用旧API

我已经读了很多关于async/await的适当使用的书,尤其是在brownfield应用程序中;例如,它非常有用。不过,我在为我的案子挣扎。如果我没有直接使用真正的异步I/O方法,例如,但我知道(或相当肯定)COM DLL在没有线程的情况下进行I/O,是吗?换句话说,线程是否会在通过旧的同步API调用的COM DLL内部的深层I/O操作中被放弃

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

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:

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}");
        });
    }
}
公共类NewApi
{
公共异步任务ConvertDocsAsync(IEnumerable docNums)
{
var oldApi=新的oldApi();
Parallel.ForEach(docNums,异步(docNum)=>
{
单据单据=空;
if(wait Task.Run(()=>!oldApi.TryCheckOutDocument(docNum,out doc)))
抛出新异常($“blah blah:{docNum}”);
doc.OtherData=“这表示转换”;
if(wait Task.Run(()=>!oldApi.TryCheckInDocument(doc)))
抛出新异常($“blah blah:{docNum}”);
});
}
}
我正在使用
Task.Run
调用旧API中的同步方法。当它们执行I/O操作时,线程是否会被放弃?如果没有,是否有更好的方法使用async/await以确保最有效地使用异步

我正在使用Task.Run调用旧API中的同步方法。当它们执行I/O操作时,线程是否会被放弃?如果没有,是否有更好的方法使用async/await以确保最有效地使用异步

没有;我担心,因为旧的API是同步的,所以不能“强制”它是异步的

如果我没有直接使用真正的异步I/O方法。。。但是我知道(或者相当肯定)COM DLL在没有线程的情况下进行I/O,仍然没有线程吗?换句话说,线程是否会在通过旧的同步API调用的COM DLL内部的深层I/O操作中被放弃

所有I/O本质上都是异步的,但在本例中,第一个同步调用会阻塞该I/O上的线程。因此,即使COM DLL是异步的,旧API也只会公开同步API—旧API会阻塞线程

另一方面,将
async
Parallel
结合使用肯定会带来痛苦的体验

目前最好的办法是保持同步:

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之前,此时您可以执行异步并发:

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);

如果我的新项目包含异步就绪调用,例如
StreamReader.readlinesync
,该怎么办。我应该如何使用我的并行方法调用它们?这里最重要的是,利用多处理器,可以同时完成多件事情。其次是线程效率(对于基于web的客户端)。显然,通过使用TPL,我消除了对UI响应性的担忧(对于基于UI的客户端)。因此,如果我不想混合使用并行和异步,我应该避免使用异步就绪方法,比如
StreamReader.readlinesync
,而只使用它们的同步对应方法吗?我会使用异步并发方法。如果你需要异步并行,那么就研究一下TPL数据流。那么在拥有多个处理器的现代计算机中,为了实现并行,使用并发方法还不够吗?换句话说,“并发”操作不是自然而然地发生在运行在操作系统认为合适的处理器上的多个线程上,从而有效地并行运行吗?我用术语“并发”来表示“一次做一件以上的事情”,用术语“并行”来表示“多个线程并行”。因此,异步和并行是不同形式的并发。感谢您的帮助。