首页 新闻 会员 周边

C#中如何将同步方法包装成异步方法

0
[待解决问题]

在封装类库的时候,可能用到第三方的类库里面一些Api, 这些api只提供了同步方法。但是,在我们封装类库时候 希望提供异步方法。这种情况怎么处理呢?

愤怒的小辣椒的主页 愤怒的小辣椒 | 初学一级 | 园豆:186
提问于:2026-07-17 16:56
< >
分享
所有回答(2)
0

Task.FromResult<>()把原始数据包装进Task<T>,异步方法不使用asyncawait关键字,因为包装方法本质是同步的,只是需要封装成看起来像异步。注意同步方法包装永远不可能变成真异步,真异步必须从底层实现。例如通过硬件驱动和系统异步API让CPU在底层硬件工作时空出来执行其他代码而不是阻塞线程等待底层结果。或者使用异步实现多线程并发,异步本质是线程池排队执行处于就绪状态任务,并在任务相关的底层硬件硬件状态变更时调整任务所在的队列。例如任务发起I/O操作的时候注册一个系统中断回调(中断触发回调把任务从等待池取出来放进就绪队列),或者在任务调度器中添加一个等待恢复的数据(调度器轮询底层操作,然后把找到的对应就绪任务放进就绪队列),注册好如何恢复任务的信息,然后把任务从就绪队列转移到等待池。Task实际上是注册阶段是一个同步代码,注册完成后自己就结束返回了,放进等待池的任务是代表后续工作的新Task,注册任务会告诉新任务准备好的数据在哪里,怎么取用。
如果是纯CPU计算型任务,同时启动等多个任务可以实现多线程并行效果,因为CPU任务不不需要等待任何东西,每个CPU核心都会连接到一个线程池线程,直到所以核心都安排了就绪任务,后续任务会被排队。这可以实现大量并发但不占用大量线程,线程池线程数框架会自动控制。

public static int Fun(int a)
{
    return a;
}

public Task<int> AsyncFun(int a)
{
    return Task.FromResult<int>(Fun(a));
}

coredx | 园豆:705 (小虾三级) | 2026-07-17 17:46

哥哥 你这个是AI回答的吗 怎么这么拗口?这里封装成异步是为了不阻塞UI

支持(0) 反对(0) 愤怒的小辣椒 | 园豆:186 (初学一级) | 2026-07-17 17:50

@愤怒的小辣椒: 如果是这样的话用TaskCompletionSource<T>来桥接。
原始方法

public static int Fun(int a)
{
    return a;
}

包装器

public Task<int> AsyncFun(int a)
{
    var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); // 可以手动控制内部任务
    // 通过Task.Run把同步方法从当前线程分离到线程池变成一个真异步方法
    _ = Task.Run(() =>
    {
        try
        {
            var r = Fun(a);
            tcs.SetResult(r);  // 设置内部任务成功并填充结果
        }
        catch(Exception e)
        {
            tcs.SetException(e); // 设置内部任务异常结束并填充异常信息方便上层调用捕获
        }
    });
    return tcs.Task; // 让上层等待手动控制的任务
}
支持(0) 反对(0) coredx | 园豆:705 (小虾三级) | 2026-07-17 18:23
0

public Task<string> DoSomethingAsync(string param)
{
return Task.Run(() =>
{
// 同步逻辑
return DoSomethingSync(param);
});
}

private string DoSomethingSync(string param)
{
return $"result:{param}";
}

生命体验之kevin-Y | 园豆:491 (菜鸟二级) | 2026-08-04 14:58
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册