gpt4 book ai didi

c# - 问题与 Task.WhenAll 并行调用 Azure 移动客户端

转载 作者:行者123 更新时间:2023-11-30 16:48:12 25 4
gpt4 key购买 nike

我的 Xamarin Android 应用程序有问题,但我相信我已将问题缩小到 Azure 移动客户端或我对 .Net 中的任务缺乏了解。我试图在控制台应用程序上重现我的问题。

我的目标是并行进行多个 api 调用。在下面的示例中,我只是重复调用以检索数据库中确实存在的用户。当我等待每次调用(GetUsersB 方法)时,一切都运行良好,但是当我尝试等待 Task.WhenAll(GetUsersA 方法)时,我几乎总是会遇到异常。

class Program
{
static void Main(string[] args)
{
var service = new MyService();
try
{
//GetUsersA(service).Wait(); //Often throws the exception attached but ocasionally is successful
GetUsersB(service).Wait(); //Never throws an exception
}
catch (AggregateException e)
{
foreach (var ex in e.InnerExceptions)
{
Console.WriteLine(e.InnerException.Message);
Console.WriteLine(e.InnerException.StackTrace);
}
}
Console.WriteLine("main done");
Console.ReadLine();
}

public async static Task GetUsersA(MyService service)
{
await Task.WhenAll(service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"),
service.GetUser("d48977fce3c6fc6b5a74c"));
Console.WriteLine("tasks complete");
}
public async static Task GetUsersB(MyService service)
{
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
await service.GetUser("d48977fce3c6fc6b5a74c");
Console.WriteLine("tasks complete");

}
}

如果需要,这里是 MyService 类

public class MyService
{
private MobileServiceClient azClient;
public MyService()
{
azClient = new MobileServiceClient("https://mysite.azurewebsites.net/");
}

public async Task<User> GetUser(string id)
{
return await azClient.GetTable<User>().LookupAsync(id);
}
}

这是内部异常的输出:

Collection was modified; enumeration operation may not execute.

at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
at Microsoft.WindowsAzure.MobileServices.MobileServiceContractResolver.CreateProperties(Type type, MemberSerialization memberSerialization)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
at Microsoft.WindowsAzure.MobileServices.MobileServiceContractResolver.CreateObjectContract(Type type)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
at Newtonsoft.Json.Linq.JToken.ToObject[T](JsonSerializer jsonSerializer)
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.<>c__DisplayClass35_0`1.<Deserialize>b__0()
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.TransformSerializationException[T](Action action, JToken token)
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.Deserialize[T](JToken json, JsonSerializer jsonSerializer)
at Microsoft.WindowsAzure.MobileServices.MobileServiceSerializer.Deserialize[T](JToken json)
at Microsoft.WindowsAzure.MobileServices.MobileServiceTable`1.<LookupAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.WindowsAzure.MobileServices.MobileServiceTable`1.<LookupAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TaskTest.MyService.<GetUser>d__2.MoveNext() in C:\Users\jalley\Documents\Visual Studio 2015\Projects\TaskTest\TaskTest\MyService.cs:line 24
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TaskTest.Program.<GetUsersA>d__1.MoveNext() in C:\Users\jalley\Documents\Visual Studio 2015\Projects\TaskTest\TaskTest\Program.cs:line 31

最佳答案

查看 source code (第 307 行)您可以很容易地看出这是 MobileServiceTable<T> 的内部设计问题。 ,这似乎不是线程安全的(我不熟悉 Xamarin)。由于您使用的是控制台应用程序,因此所有任务都被卸载到线程池,并且并行性可能(并且将会)发生在第 307 行。从这一点开始,您有多个线程迭代同一个字典,而其他线程修改它。如果你再看看MobileServiceContractResolver ,您会看到一些使用“id”属性作为内部使用的缓存键的序列化,它可能与代码中的“d48977fce3c6fc6b5a74c”键相同。

这不是一个完整的答案,因为您的代码 看起来还不错。我认为这里不会有“真正的答案”,因为即使您可能过早地使用 async/await,您的代码也是完全有效的。我只是觉得您可能想知道为什么会发生这种情况。

这个库可能用于单线程上下文之上,例如 ASP.NET 或 UI 应用程序,而不是控制台应用程序。

关于c# - 问题与 Task.WhenAll 并行调用 Azure 移动客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38441850/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com