如何在 C# 中设计并行 web api? [英] How to design parallel web api in c#?

查看:54
本文介绍了如何在 C# 中设计并行 web api?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试设计一个可以从外部服务器获取数据但有限制的 Web api.我想弄清楚如何最好地设计它以提高效率.

I am trying to design a web api that can get data from an external server but with limitations. I'm trying to figure out how best to design it to be efficient.

我的 api 有一个接受输入的端点.它是一个类似于 tom@domain.com 的域名.然后,我的端点对域进行 http 调用以获取身份验证令牌,然后使用用户名再次调用该域以获取返回给客户端的一些数据.但是我的 api 可以接受多个用户名(逗号分隔,如 ?users=tom@domain.a.com, bill@domain.b.com).我的网络服务器知道每个域的最大并行连接数是多少.

My api has an endpoint that takes an input. It is is a domain name like tom@domain.com. My endpoint then makes an http call to the domain to get an auth token, then makes another call to that domain with the username to get some data which is returned to the client. However my api can accept multiple usernames (comma delimited like ?users=tom@domain.a.com, bill@domain.b.com). My web server knows for each domain what is the max parallel connections I can make to get the data.

所以问题是如何组织数据,以便我可以最大化并行计算但不超出限制.

So the problem is how to organize the data so I can maximize parallel computing but stay within the limits.

这是我的想法:

首先解析用户列表并将它们分组.然后有一个静态字典.键是域,值是一个有 2 个队列的自定义对象.两个队列都包含一个 Tasks 列表(来自 async/await).但是,第一个队列最大长度将是该域的限制值.

First parse the user list and group them up. Then have a static dictionary. Key is domain, value is a custom object which has 2 queues. Both queues holds a list of Tasks (from async/await). However the first queue max length will be the value of the limit for that domain.

?users=bill@D.com, max@D.com, sarah@A.com, tom@D.com

dictionary = {
    "D.com" : [
         [],
         ["bill@D.com", "max@D.com", "tom@D.com"]
     ],
     "A.com" : [
         [],
         ["sarah@A.com"]
     ]
}

然后我可以每秒运行一个代码,它循环遍历所有字典值,并用第二个队列中尽可能多的 Task 对象填充第一个队列(即从第二个队列中删除并首先放入),使其在限制.

Then I can run a code every second, which loops through all dictionary values, and fills the first queue with as many Task objects from the second queue (.e. removing from 2nd queue and putting in first) so its within the limit.

一旦它在第一个队列中,任务就会使用 Parallel.Invoke() 执行,然后当任务完成时它会从第一个队列中删除(除非有一些请求正在等待它,解释在下一段).

As soon as its in the first queue, the task executes using Parallel.Invoke() then when the task is completed it gets removed from first queue (unless some request is waiting for it, explained in next paragraph).

我这样做是因为如果向我的端点发出另一个 api 请求,其中一些名称已经来自第一个请求,我想重用它.因此,如果它在第一个队列中,我会对该任务调用 await.

I do this because if another api request is made to my endpoint with some names thats already from the first request, I want to reuse it. So If it's in the first queue, I call await on that Task.

不知何故,当任务完成时,我需要知道没有其他人在任务中等待该用户,在这种情况下,将其从第一个队列中删除.此外,如果客户端断开连接,它应该删除对该客户端的用户部分的监视.

Somehow when a task finishes, I need to know that no other people are waiting for that user in the task, and in that case, remove it from the first queue. Also if a client disconnects it should remove the watching of the users part for that client.

有谁知道这是否是一个好方法?

Does anyone know if this is a good approach?

推荐答案

由于它是并行的,您马上就知道您可能需要使用 System.Collections.Concurrent,并且由于您需要键/值查找(用户标识符/HTTP 响应)你需要一个 ConcurrentDictionary.由于所有用户都有一个公共缓存,因此您需要将其存储在一个静态变量中,该变量可用于所有线程和所有 HTTP 请求.

Since it's parallel, you know right away you're probably going to need to use System.Collections.Concurrent, and since you need key/value lookup (user identifier/HTTP response) you need a ConcurrentDictionary. And since there is a common cache for all users, you will want to store it in a static variable, which is available to all threads and all HTTP requests.

这是一个简单的例子:

public class MyCacheClass
{
    //Store the list of users/requests
    static private ConcurrentDictionary<string, Task<HttpResponseMessage>> _cache = new ConcurrentDictionary<string, Task<HttpResponseMessage>>();

    //Get from the ConcurrentDictionary or add if it's not there
    public async Task<HttpResponseMessage> GetUser(string key)
    {
        return await _cache.GetOrAdd(key, GetResponse(key));
    }

    //You just to implement this method, potentially in a subclass, to get the data
    protected virtual async Task<HttpResponseMessage> GetResponse(string key)
    {
        var httpClient = new HttpClient();
        var url = string.Format(@"http://www.google.com?q={0}", key);
        return await httpClient.GetAsync(url);
    }
}

然后要获取用户的信息,只需调用:

Then to get a user's information, just call:

var o = new MyCacheClass();
var userInfo = await o.GetUser(userID);

注意:如果您打算在生产系统上使用这样的代码,您可能会考虑添加一些在一段时间后或达到特定大小时清除或修剪缓存的方法.否则,您的解决方案可能无法按您需要的方式扩展.

Note: If you're going to use code like this on a production system, you might consider adding some means of purging or trimming the cache after a period of time or when it reaches a certain size. Otherwise your solution may not scale the way you need it to.

这篇关于如何在 C# 中设计并行 web api?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆