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

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

问题描述

我正在尝试设计一个Web api,该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).我的Web服务器知道每个域可以获取数据的最大并行连接数.

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列表(来自异步/等待).但是,第一个队列的最大长度将是该域的限制值.

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天全站免登陆