C#+ WinRT + Monogame线程用于网络(Azure移动服务)操作

C# + WinRT + Monogame threading for network (Azure Mobile Service) operations
2021-06-10
  •  译文(汉语)
  •  原文(英语)

我的应用程序中有一个循环,它以下列方式循环通过一组实体

foreach(var entity in mEntities)
{
    entity.Update();
}

其中一些实体维护一个网络组件,该组件将调用Azure移动服务以将其状态更新到服务器.下面是一个示例:

public class TestEntity {
    public int Index;
    public int PropertyValue;

    public async void Update()
    {
        Task.Run(() => {
            MyAzureMobileServiceClient.Update(Index, PropertyValue);
        });
    }
}

UI渲染由Monogame以更传统的游戏循环方式完成.虽然我不知道它的内部工作原理,但我可以肯定地说它没有实际的独立线程来工作.实际上,这表示每次调用此更新时UI冻结.

我希望能够在后台"平稳"运行它.在旧的Windows模型中,可以通过启动一个可以处理它的新线程来轻松完成此操作,但是我对WinRT中的线程不够了解,无法理解我的方法出了什么问题.

有任何想法吗?

[更新]我也尝试过这个:

Task.Factory.StartNew(async () =>
{
    while(true) {
        await Task.Delay(1000);
        MyAzureMobileServiceClient.Update(Index, PropertyValue);
    }
});

每隔1秒钟,我会像以前一样进行一次迷你冻结.

[更新2]我尝试了一下.我用一个标准的HTTP请求替换了Azure移动服务客户端调用,它的运行非常出色.没有小冻结.当然还不是后端,但是至少我可以手动完成整个工作.但是宁愿不这样做.

[更新3]这变得越来越奇特.我意识到我简化了此问题中的代码,以使其在上下文中具有连贯性.但是,这似乎已经消除了问题的真正根源.我尝试了以下操作:

  1. 我创建了一个HTTP请求并手动创建了该请求,并在Task.Run()内部对其进行了调用,并且该请求运行出色,没有任何延迟.
  2. 我将Azure移动服务客户端直接称为"更新",并且没有延迟.

因此,这将我带到了问题所在.我基本上有一个Azure移动服务的包装器类.实际的路径大致如下所示:

CommunicationClient.UpdateAsync(myObject);

public Task UpdateAsync(MyObjectType obj)
{
    var table = mMobileServiceClient.GetTable<MyObjectType>();
    return table.UpdateAsync(obj);
}

这会导致滞后,但是如果我代替滞后,则不会出现任何延迟:

var client = CommunicationClient.MobileServiceClient;
var table = client.GetTable<MyObjectType>();
table.UpdateAsync(obj);

太...我可能应该重构整个问题.它越来越干了.

速聊1:
在这里很难看到所有活动部件是如何装配在一起的.是数据请求导致暂停还是使用获取的数据更新UI?如果是后者,那就是更大的挑战.
速聊2:
正是后者,这将使其成为挑战.基本上,我目前甚至不更新用户界面,而只是发送请求.我的原始帖子在我为我的应用程序使用Azure移动服务后端方面不准确.实际上,这意味着发送HTTP请求并获取响应.也许我的代码中某处出现了一个愚蠢的用户错误,导致我的Update线程等待响应.我可能会更深入地研究Monogame如何处理渲染.如果有帮助,则从Monogame更新循环中调用该Update().
速聊3:
我应该补充一点,我正在等待的响应仅仅是"200 OK"或"### Error".不需要实际数据,无论如何我对返回的结果并不感兴趣.此外,发送的数据是一个简单的小型"jsonized"结构,其中包含几个字符串和一些整数.就是说,移动的数据量确实很小.
速聊4:
您可能会调查调度程序是否将任务内联到同一线程中,而不是创建一个新线程.C#中的默认行为是允许这样做.您可以通过将任务标记为长时间运行来暗示不应这样做.即:Task.Factory.StartNew(Action,TaskCreationOptions.LongRunning);
解决过程1

我有一个关于如何在backgroundthread上运行东西的问题,他们建议我使用ThreadPool,所以我建议您查看我的问题及其答案,也许您可​​以了解一些事情并最终解决问题.

创建Backgroundthread Monogame

I have a loop in my application that loops through a set of entities in the following fashion

foreach(var entity in mEntities)
{
    entity.Update();
}

Some of these entities maintain a networking component that will call a Azure Mobile Service in order to update their state to the server. An example is below:

public class TestEntity {
    public int Index;
    public int PropertyValue;

    public async void Update()
    {
        Task.Run(() => {
            MyAzureMobileServiceClient.Update(Index, PropertyValue);
        });
    }
}

The UI rendering is done by Monogame in a more traditional game loop fashion. Whilst I do not know the inner workings of it, I am fairly certain that it does not have an actual separate thread doing the work. In practice, this shows as the UI freezing every time this update is called.

I want to be able to run it "smoothly" in the background. In the old Windows model this could have easily been done by starting a new Thread that would handle it, but I don't understand the threading well enough in WinRT to understand what is wrong with my approach.

Any ideas?

[update] I also tried this:

Task.Factory.StartNew(async () =>
{
    while(true) {
        await Task.Delay(1000);
        MyAzureMobileServiceClient.Update(Index, PropertyValue);
    }
});

Every 1 seconds, I get a mini-freeze like before.

[update 2] I tried this with a twist. I replaced the Azure Mobile Service client call with a standard HTTP request and it worked splendidly; no mini-freezes. Granted it wasn't to the backend yet, but at least I have a work around by doing the whole thing manually. Would prefer to not do that, however.

[update 3] This is getting peculiar. I realize I simplified the code in this question in order to get it coherent in the context. However, this appears to have removed the true source of the problem. I tried the following things:

  1. I created a HTTP request and created the request manually, called it inside the Task.Run() and it worked splendidly with no latency.
  2. I called the Azure Mobile Service client Update DIRECTLY and there was no latency.

So this brings me to where the problem lies. I basically have a wrapper class for the Azure Mobile Service. The real path that goes looks roughly like this:

CommunicationClient.UpdateAsync(myObject);

public Task UpdateAsync(MyObjectType obj)
{
    var table = mMobileServiceClient.GetTable<MyObjectType>();
    return table.UpdateAsync(obj);
}

This causes the lag, but if I do this instead of it, it works with no latency whatsoever:

var client = CommunicationClient.MobileServiceClient;
var table = client.GetTable<MyObjectType>();
table.UpdateAsync(obj);

Soooooo... I should probably refactor the whole question. It's getting tl;dry.

Talk1:
It's a bit hard to see how all of the moving parts fit together here. Is it the data request that's causing the pause or updating the UI with the fetched data? If it's the latter, that's a much bigger challenge.
Talk2:
It's the latter and that would make it the challenge. Basically I don't currently even update the UI but just send a request. My original post was inaccurate to the extent that I am using Azure Mobile Service backend for my app. In practice this means sending an HTTP request and getting the response. Maybe there is a stupid user error somewhere in my code that causes my Update thread to await for the response. I could probably delve deeper into how Monogame handles the rendering. If it helps, that Update() is called from the Monogame update loop.
Talk3:
I should add that the response I'm waiting for is a mere "200 OK" or "### Error". No actual data is required and I am not really interested in what is returned anyway. Furthermore, the data sent is a simple small "jsonized" struct containing a couple of strings and a few integers. That's to say that the amount of data moved is really small.
Talk4:
You may look into whether the scheduler is inlining your task onto the same thread instead of creating a new thread. The default behavior in C# is to allow this. You can hint that it shouldn't by marking your task as long running. ie: Task.Factory.StartNew(Action, TaskCreationOptions.LongRunning);
Solutions1

I had a question about how to run things on a backgroundthread and they advised me to use ThreadPool so I would advise you to look at my question and the answer on it maybe you can pick up on some things and get it working on your end.

Create Backgroundthread Monogame

转载于:https://stackoverflow.com/questions/19081531/c-sharp-winrt-monogame-threading-for-network-azure-mobile-service-operatio

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入