异步编程是用于推迟具有高延迟或低优先级的操作的策略,通常旨在提高软件的性能,响应性和/或可组合性。这些策略通常使用事件驱动编程和回调的某种组合来使用,并且可选地通过协同程序和/或线程来使用并发。
在 C# 中将 Task<T> 转换为 Task<object>,无需 T
我有一个充满扩展方法的静态类,其中每个方法都是异步的并返回一些值 - 像这样: 公共静态类 MyContextExtensions{ 公共静态异步任务 我有一个充满扩展方法的静态类,其中每个方法都是异步的并返回一些值 - 像这样: public static class MyContextExtensions{ public static async Task<bool> SomeFunction(this DbContext myContext){ bool output = false; //...doing stuff with myContext return output; } public static async Task<List<string>> SomeOtherFunction(this DbContext myContext){ List<string> output = new List<string>(); //...doing stuff with myContext return output; } } 我的目标是能够从另一个类中的单个方法调用这些方法中的任何一个,并将其结果作为对象返回。它看起来像这样: public class MyHub: Hub{ public async Task<object> InvokeContextExtension(string methodName){ using(var context = new DbContext()){ //This fails because of invalid cast return await (Task<object>)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context); } } } 问题是转换失败。我的困境是我无法将任何类型参数传递给“InvokeContextExtension”方法,因为它是 SignalR 中心的一部分并且由 javascript 调用。在某种程度上,我不关心扩展方法的返回类型,因为它只会序列化为 JSON 并发送回 javascript 客户端。但是,我确实必须将 Invoke 返回的值转换为任务才能使用等待运算符。我必须为该“任务”提供一个通用参数,否则它将把返回类型视为 void。因此,这一切都归结为如何成功地将具有通用参数 T 的任务转换为具有对象通用参数的任务,其中 T 表示扩展方法的输出。 您可以分两步完成 - await使用基类执行任务,然后使用反射或dynamic收获结果: using(var context = new DbContext()) { // Get the task Task task = (Task)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context); // Make sure it runs to completion await task.ConfigureAwait(false); // Harvest the result return (object)((dynamic)task).Result; } 这是一个完整的运行示例,它将上述通过反射调用 Task 的技术置于上下文中: class MainClass { public static void Main(string[] args) { var t1 = Task.Run(async () => Console.WriteLine(await Bar("Foo1"))); var t2 = Task.Run(async () => Console.WriteLine(await Bar("Foo2"))); Task.WaitAll(t1, t2); } public static async Task<object> Bar(string name) { Task t = (Task)typeof(MainClass).GetMethod(name).Invoke(null, new object[] { "bar" }); await t.ConfigureAwait(false); return (object)((dynamic)t).Result; } public static Task<string> Foo1(string s) { return Task.FromResult("hello"); } public static Task<bool> Foo2(string s) { return Task.FromResult(true); } } 一般来说,要将 Task<T> 转换为 Task<object>,我会简单地采用简单的连续映射: Task<T> yourTaskT; // .... Task<object> yourTaskObject = yourTaskT.ContinueWith(t => (object) t.Result); (文档链接在这里) 但是,您实际的具体需求是 通过反射调用 Task 并获取其(未知类型)结果 。 为此,您可以参考完整的dasblinkenlight的答案,它应该适合您的具体问题。 我想提供一个实现,恕我直言,这是早期答案的最佳组合: 精确的参数处理 无动态调度 通用扩展方法 给你: /// <summary> /// Casts a <see cref="Task"/> to a <see cref="Task{TResult}"/>. /// This method will throw an <see cref="InvalidCastException"/> if the specified task /// returns a value which is not identity-convertible to <typeparamref name="T"/>. /// </summary> public static async Task<T> Cast<T>(this Task task) { if (task == null) throw new ArgumentNullException(nameof(task)); if (!task.GetType().IsGenericType || task.GetType().GetGenericTypeDefinition() != typeof(Task<>)) throw new ArgumentException("An argument of type 'System.Threading.Tasks.Task`1' was expected"); await task.ConfigureAwait(false); object result = task.GetType().GetProperty(nameof(Task<object>.Result)).GetValue(task); return (T)result; } 您不能将 Task<T> 转换为 Task<object>,因为 Task<T> 不是协变的(也不是逆变的)。最简单的解决方案是使用更多反射: var task = (Task) mi.Invoke (obj, null) ; var result = task.GetType ().GetProperty ("Result").GetValue (task) ; 这很慢且效率低下,但如果不经常执行此代码则可用。顺便说一句,如果您要阻塞等待其结果,那么异步 MakeMyClass1 方法有什么用呢? 另一种可能性是为此目的编写一个扩展方法: public static Task<object> Convert<T>(this Task<T> task) { TaskCompletionSource<object> res = new TaskCompletionSource<object>(); return task.ContinueWith(t => { if (t.IsCanceled) { res.TrySetCanceled(); } else if (t.IsFaulted) { res.TrySetException(t.Exception); } else { res.TrySetResult(t.Result); } return res.Task; } , TaskContinuationOptions.ExecuteSynchronously).Unwrap(); } 它是非阻塞解决方案,将保留任务的原始状态/异常。 最有效的方法是自定义等待者: struct TaskCast<TSource, TDestination> where TSource : TDestination { readonly Task<TSource> task; public TaskCast(Task<TSource> task) { this.task = task; } public Awaiter GetAwaiter() => new Awaiter(task); public struct Awaiter : System.Runtime.CompilerServices.INotifyCompletion { System.Runtime.CompilerServices.TaskAwaiter<TSource> awaiter; public Awaiter(Task<TSource> task) { awaiter = task.GetAwaiter(); } public bool IsCompleted => awaiter.IsCompleted; public TDestination GetResult() => awaiter.GetResult(); public void OnCompleted(Action continuation) => awaiter.OnCompleted(continuation); } } 具有以下用法: Task<...> someTask = ...; await TaskCast<..., object>(someTask); 这种方法的局限性在于结果不是 Task<object> 而是一个可等待的对象。 我根据dasblinkenlight的回答做了一个小小的扩展方法: public static class TaskExtension { public async static Task<T> Cast<T>(this Task task) { if (!task.GetType().IsGenericType) throw new InvalidOperationException(); await task.ConfigureAwait(false); // Harvest the result. Ugly but works return (T)((dynamic)task).Result; } } 用途: Task<Foo> task = ... Task<object> = task.Cast<object>(); 这样您就可以将 T 中的 Task<T> 更改为您想要的任何内容。 对于最佳方法,不使用反射和动态丑陋语法,也不传递泛型类型。我将使用两种扩展方法来实现这个目标。 public static async Task<object> CastToObject<T>([NotNull] this Task<T> task) { return await task.ConfigureAwait(false); } public static async Task<TResult> Cast<TResult>([NotNull] this Task<object> task) { return (TResult) await task.ConfigureAwait(false); } 用途: Task<T1> task ... Task<T2> task2 = task.CastToObject().Cast<T2>(); 这是我的第二种方法,但不推荐: public static async Task<TResult> Cast<TSource, TResult>([NotNull] this Task<TSource> task, TResult dummy = default) { return (TResult)(object) await task.ConfigureAwait(false); } 用途: Task<T1> task ... Task<T2> task2 = task.Cast((T2) default); // Or Task<T2> task2 = task.Cast<T1, T2>(); 这是我的第三种方法,但是不推荐:(类似于第二种) public static async Task<TResult> Cast<TSource, TResult>([NotNull] this Task<TSource> task, Type<TResult> type = null) { return (TResult)(object) await task.ConfigureAwait(false); } // Dummy type class public class Type<T> { } public static class TypeExtension { public static Type<T> ToGeneric<T>(this T source) { return new Type<T>(); } } 用途: Task<T1> task ... Task<T2> task2 = task.Cast(typeof(T2).ToGeneric()); // Or Task<T2> task2 = task.Cast<T1, T2>(); 将 await 与动态/反射调用混合使用并不是一个好主意,因为 await 是一条编译器指令,它会围绕调用的方法生成大量代码,并且使用更多反射来“模拟”编译器工作并没有真正的意义,延续、包装等 因为您需要的是在运行时管理代码,然后忘记在编译时工作的 asyc await 语法糖。重写 SomeFunction 和 SomeOtherFunction 而不使用它们,并在运行时创建的您自己的任务中开始操作。您将得到相同的行为,但代码非常清晰。
有没有办法让javascript的await关键字在异步函数之外工作?我希望能够冻结整个调用堆栈(而不仅仅是异步函数的其余部分),以恢复...
以下代码会产生预期的输出 函数toppings_choice() { 返回新的 Promise((解决, 拒绝) => { 设置超时(()=> { 解决(console.log(“哪个浇头
我想分享我的将异步编程与机器学习相结合的计划和想法,所以这是我的想法:让我们考虑以下代码: 将 pandas 导入为 pd 来自 sklearn.ensemble
Python 异步请求抛出错误:对象 NoneType 不能在“await”表达式中使用
我正在使用streamlit hello示例应用程序测试tornado websocket api, 我向tornado.websocket.WebSocketHandler get方法添加了一个异步包装器来记录websocket连接 #pip3安装
数据库没有数据时,有一个页面显示No user。当数据库中有数据时,显示真实数据。代码如下 const [用户,setUsers] = useStat...
既然同步意味着同时,而常规的javascript是按顺序、一行一行地运行的,为什么js的同步不称为异步呢?同样,为什么异步不称为同步...
背景: 我正在创建我想要开源的库。 该库设计用于后端进程。 我将提供的服务利用 Java 的 ProcessBuilder 来执行
SequelizeConnectionAcquireTimeoutError:操作超时
请理解这种情况,我需要帮助来解决这个问题。 如果有人能帮助我找出问题并解决,我将奖励他 5rrr,最高 15 美元。 我正在使用的后端是
Django Rest Framework 异步错误:“'async_generator' 对象不可迭代”
我正在开发一个带有异步视图的 Django Rest Framework 项目。我有一个用于流式响应的端点,这是我的代码: 从 adrf.views 导入 APIView 作为视图 ChatAPI 类(视图):
我有以下代码: 导入异步 异步 def test_1(): res1 = 等待 foo1() 返回res1 异步 def test_2(): res2 = 等待 foo2() 返回res2 如果 __name__ == '__m...
Await 是 es7 中一个令人惊叹的功能。 然而,每次我使用await时,我发现我必须定义一个异步函数并调用这个函数。 例如 异步函数 asy(){ const [resCityGu...
我编写了一个 Node.js API,可以从集合中读取数据。包含 1000 条记录的集合。每条记录包含 300 个子有效负载数据点。 const 数据 = 等待 csvModel['csvFiles'].find({ &...
为了理解 C# 中的异步编程,我创建了以下函数: 异步任务 Do() { Console.WriteLine("开始 1"); Console.WriteLine("开始 2 ”); 等待T...
为了更好地理解 C# 中的异步编程,我编写了以下函数: 异步任务 Do() { Console.WriteLine("开始 1"); Console.WriteLine("开始 2 ”); 等待
我有一个 vue 模板,其中有一个表格呈现数组的所有项目,看起来非常像这样: 我的桌头... 我有一个 vue 模板,其中有一个表格呈现数组的所有项目,看起来很像这样: <template> <thead> my table heads... </thead> <tr v-for="item in items" my items </tr> </template> 我有一个函数可以让我过滤数据库并替换项目数组的值。我的脚本标签如下所示: <script> data(){ return: { items: [] } }, methods: { async getList(){ here i do my query... .then(this.items = response.data) }, async filter(){ here i do my query with my filterObj... .then(this.items = response.data) }, async mounted(){ this.getList() } 这个效果很好。我开始过滤,vue 的 reactiviy 自动用新数据重新加载我的表。问题是我注意到有时过滤器会“自行取消”并调用“getList”函数。我在该函数上添加了一个 console.log() ,我注意到首次加载页面时它会被调用 7-8 次,并且在应用过滤器后有时会随机调用它。有什么想法吗? 我读到了这个:https://github.com/vitejs/vite/issues/9231 我是用vite来编译的。这可能是我的问题吗?任何人都可以在项目中重现这个吗? 我注意到 Mounted() 属性中的函数被调用了几次 谢谢大家,我知道发生了什么事,我想让这个,因为它可能会帮助像我这样的菜鸟在未来 我在每个表格行上调用了一个组件,因此您可以单击它们并打开该对话框。问题是,由于某种原因,我在该组件上在 Mounted() 对象上调用了 $emit 。可能是我测试的时候忘记删掉了。这个 $emit 配置为触发我在父组件上的 Mounted() 对象上的函数,因此看起来它被调用了几次。太蠢了 谢谢大家的帮助
将异步等待中基于id的两个json数组合并到javascript中
我有以下这些 json 数组。 常量 arrA = [ { id: '12', 通用 ID: 'B143', 总数:10, }, { id: '12', 通用 ID: 'B145', 总数:20, }, { id: '13', 根...
我正在尝试传递一个异步函数,该函数是我在二进制应用程序的模块中定义的,作为我在同一个 Rust 应用程序中开发的通用函数的参数。 通用
元上下文: 我正在使用 aiohttp 构建一个 api。由于它是一个异步框架,因此我必须使用 async 来定义处理程序。例子: 异步 def index_handler(请求): 返回 web.Response(t...
我正在第一次尝试 asyncio botocore 实现。然而,我很确定我没有得到预期的异步性,可能是因为我自己缺乏这方面的经验。 :) b的目标...