C# 如何为HttpClient.GetStreamAsync()等异步方法编写代码?

C# 如何为HttpClient.GetStreamAsync()等异步方法编写代码?,c#,async-await,c#-5.0,C#,Async Await,C# 5.0,详细说明一下,我想知道的是如何异步启动任务,就像在HttpClient.GetStreamAsync()等异步方法中所做的那样 示例代码如下所示: static async Task<string> LengthyOperation() { Console.WriteLine("Executing a lengthy operation..."); Debug.WriteLine("LENGTHY THREAD ID: " + Thre

详细说明一下,我想知道的是如何异步启动任务,就像在HttpClient.GetStreamAsync()等异步方法中所做的那样

示例代码如下所示:

    static async Task<string> LengthyOperation()
    {
        Console.WriteLine("Executing a lengthy operation...");
        Debug.WriteLine("LENGTHY THREAD ID: " + Thread.CurrentThread.ManagedThreadId);

        var task = new Task(() =>
            {
                Debug.WriteLine("TASK THREAD ID: " + Thread.CurrentThread.ManagedThreadId);
                for (int i = 0; i < 10000; i++)
                {
                    File.ReadAllLines("abc.txt");
                    counter++;
                }
            });

        task.Start();
        await task;
    }
静态异步任务长度操作()
{
WriteLine(“执行冗长的操作…”);
WriteLine(“冗长的线程ID:+THREAD.CurrentThread.ManagedThreadId”);
变量任务=新任务(()=>
{
WriteLine(“任务线程ID:+THREAD.CurrentThread.ManagedThreadId”);
对于(int i=0;i<10000;i++)
{
ReadAllLines(“abc.txt”);
计数器++;
}
});
task.Start();
等待任务;
}
在这种情况下,主线程id(LengthyOperation方法在其上运行)与此任务在其上运行的主线程id不同。

长线程ID不应该与任务线程ID相同吗?

您可以使用
TaskScheduler

样品

TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
task.Start(scheduler); //use the schedular
结果

LENGTHY THREAD ID: 8
TASK THREAD ID: 8

其实很简单,不过你需要另一种方法

private async Task LongTaskImpl()
{
    Debug.WriteLine("TASK THREAD ID: " + Thread.CurrentThread.ManagedThreadId);
    for (int i = 0; i < 10000; i++)
    {
       File.ReadAllLines("abc.txt");
       counter++;
    }
}    

static async Task LengthyOperation()
{
    Console.WriteLine("Executing a lengthy operation...");
    Debug.WriteLine("LENGTHY THREAD ID: " + Thread.CurrentThread.ManagedThreadId);

    var task = LongTaskImpl();
    await task;
}
专用异步任务LongTaskImpl()
{
WriteLine(“任务线程ID:+THREAD.CurrentThread.ManagedThreadId”);
对于(int i=0;i<10000;i++)
{
ReadAllLines(“abc.txt”);
计数器++;
}
}    
静态异步任务长度操作()
{
WriteLine(“执行冗长的操作…”);
WriteLine(“冗长的线程ID:+THREAD.CurrentThread.ManagedThreadId”);
var task=LongTaskImpl();
等待任务;
}
现在,您有了一个任务,该任务与它的调用者在同一个线程上运行。 但是,您的代码中没有异步内容,因此它将同步运行。只是将某个内容转换为任务并不意味着它会神奇地变为异步,您必须为此调用(并等待)一些异步操作)

如何像HttpClient.GetStreamAsync()等异步方法那样异步启动任务

理想情况下,只有自然异步方法(如I/O)公开异步API。这通常通过
Task.Factory.fromsync
TaskCompletionSource
完成

例如:

静态任务MyOpAsync()
{
var tcs=new TaskCompletionSource();
…//建立一个回调,在操作完成时调用tcs.TrySetResult
返回tcs.Task;
}

如果希望它在同一个线程上运行,为什么要将其作为一项任务?为什么不把代码放在LengthyOperation方法中(或者作为常规方法调用调用内部内容)?让一个任务与调用者在同一个线程上执行有什么意义?我不明白:
task
中的代码是完全同步的,你想在当前线程上运行它,那么,为什么要使用
任务
s呢?如果希望
LengthyOperation()
是异步的,那么这种异步必须来自某个地方:要么来自在另一个线程上运行代码,要么(更好)来自使用实际的异步操作,比如
StreamReader.ReadToEndAsync()
(在
文件上没有异步操作).@I3arnon如果任务中的代码包含一些
await
s,那么在同一线程上执行同步部分通常是有意义的。@svick好的,这就是同步上下文的作用-确保等待继续在原始线程上执行。但对于任务本身来说,这真的毫无意义(除了一些奇怪的合作多任务场景)。为什么会投反对票?当然,这是个坏主意,但它确实回答了这个问题。@Luaan我的想法是一样的,OP被要求在调用线程上调用任务,以便两者都显示相同的ID。感谢您发布结果。不过我得自己试试:)这似乎是个好主意。我只是想试试,谢谢。事实上,我知道这是同步的。毕竟,这只是一个示例代码:)现在这正是我想要的。谢谢你,斯蒂芬!遗憾的是,我还没有足够的声誉,所以我不能对你的答案投赞成票。@好奇的是,如果这正是你一直在寻找的,那么你可以接受它。
static Task MyOpAsync()
{
  var tcs = new TaskCompletionSource<object>();
  ... // Establish a callback that calls tcs.TrySetResult when the operation completes
  return tcs.Task;
}