我有一个场景,我的BaseRepository在很短的时间内得到了很多命令。在其他时刻,这种情况不会发生。我想要达到的是节流这些命令。也就是说,当命令必须执行时,等待任何其他调用的短时间(0.2s)。如果没有创建,则执行命令(转到数据库)。如果其他人被制造,请重置计时器。这样,在添加了所有命令之后,我们可以在一个连接上执行所有命令。
这就是我实现它的方式,我想知道有什么评论:
public BaseRepository()
{
_throttledActions = new List<Action<Entities>>();
_timer = new Timer(ExecuteThrottledActions);
}
protected void Execute(Action<Entities> action)
{
lock (_locker)
{
_throttledActions.add(action);
}
_timer.Change(TimeSpan.FromSeconds(0.2), TimeSpan.FromMilliseconds(-1));
}
private void ExecuteThrottledActions(object state)
{
var throttledActionsCopy = new List<Action<Entities>>();
lock (_locker)
{
throttledActionsCopy.AddRange(_throttledActions);
_throttledActions.Clear();
}
using (var scope...)
{
using (var entities = new Entities())
{
foreach (var throttledAction in throttledActionsCopy)
{
throttledAction(entities);
}
}
}
}这允许我在继承自BaseRepository的类中执行以下操作:
public void Save(Customer customer)
{
Executed(e => e.Customers.AddObject(customer);
}如果对Save方法进行了大量调用,我将保存它们并在一个使用语句下执行它们,因此在一个连接下执行它们。
简言之,我所做的是:
我将操作复制到另一个列表(带有锁定),因为我不希望其他调用干扰我正在循环的集合(并且在执行完所有操作后清除)。
有什么评论吗?
发布于 2015-01-19 17:15:51
有一个大问题:如果你不断收到请求,那么就有可能饿死执行者。
您可以通过测试列表的大小来解决这个问题,如果列表变得太大,则不要重置计时器,
protected void Execute(Action<Entities> action)
{
bool resetTimer;
lock (_locker)
{
_throttledActions.add(action);
reset = _throttledActions.size() < MaxSize;
}
if(resetTimer)
_timer.Change(TimeSpan.FromSeconds(0.2), TimeSpan.FromMilliseconds(-1));
}或者,您可以使用第二个较慢的计时器,它不会被重置,只是经常运行来清除列表,不管等待了多长时间,还有多少动作可能还在后面。
https://codereview.stackexchange.com/questions/77992
复制相似问题