gpt4 book ai didi

c# - 在 HttpModule 中正确使用 ConcurrentQueue?

转载 作者:行者123 更新时间:2023-11-30 17:54:57 25 4
gpt4 key购买 nike

我正在尝试为使用异步编程处理图像的 HttpModule 添加速度提升。

虽然看起来我确实获得了性能改进,但我想检查我是否正确使用了提供的工具。

我特别担心我对队列的处理不正确。

我正在采用的方法。

  1. 初始化并发队列
  2. 将 ProcessImage 方法添加到队列中AddOnBeginRequestAsync 中的 BeginEventHandler
  3. 在 EndEventHandler 中处理队列AddOnBeginRequestAsync

有很多代码所以我提前道歉但是异步编程很难:

字段

/// <summary>
/// The thread safe fifo queue.
/// </summary>
private static ConcurrentQueue<Action> imageOperations;

/// <summary>
/// A value indicating whether the application has started.
/// </summary>
private static bool hasAppStarted = false;

http模块初始化

/// <summary>
/// Initializes a module and prepares it to handle requests.
/// </summary>
/// <param name="context">
/// An <see cref="T:System.Web.HttpApplication"/> that provides
/// access to the methods, properties, and events common to all
/// application objects within an ASP.NET application
/// </param>
public void Init(HttpApplication context)
{
if (!hasAppStarted)
{
lock (SyncRoot)
{
if (!hasAppStarted)
{
imageOperations = new ConcurrentQueue<Action>();
DiskCache.CreateCacheDirectories();
hasAppStarted = true;
}
}
}

context.AddOnBeginRequestAsync(OnBeginAsync, OnEndAsync);
context.PreSendRequestHeaders += this.ContextPreSendRequestHeaders;

}

事件处理程序

/// <summary>
/// The <see cref="T:System.Web.BeginEventHandler"/> that starts
/// asynchronous processing
/// of the <see cref="T:System.Web.HttpApplication.BeginRequest"/>.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// An <see cref="T:System.EventArgs">EventArgs</see> that contains
/// the event data.
/// </param>
/// <param name="cb">
/// The delegate to call when the asynchronous method call is complete.
/// If cb is null, the delegate is not called.
/// </param>
/// <param name="extraData">
/// Any additional data needed to process the request.
/// </param>
/// <returns></returns>
IAsyncResult OnBeginAsync(
object sender, EventArgs e, AsyncCallback cb, object extraData)
{
HttpContext context = ((HttpApplication)sender).Context;
EnqueueDelegate enqueueDelegate = new EnqueueDelegate(Enqueue);

return enqueueDelegate.BeginInvoke(context, cb, extraData);

}

/// <summary>
/// The method that handles asynchronous events such as application events.
/// </summary>
/// <param name="result">
/// The <see cref="T:System.IAsyncResult"/> that is the result of the
/// <see cref="T:System.Web.BeginEventHandler"/> operation.
/// </param>
public void OnEndAsync(IAsyncResult result)
{
// An action to consume the ConcurrentQueue.
Action action = () =>
{
Action op;

while (imageOperations.TryDequeue(out op))
{
op();
}
};

// Start 4 concurrent consuming actions.
Parallel.Invoke(action, action, action, action);
}

委托(delegate)和处理

/// <summary>
/// The delegate void representing the Enqueue method.
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that
/// provides references to the intrinsic server objects
/// </param>
private delegate void EnqueueDelegate(HttpContext context);

/// <summary>
/// Adds the method to the queue.
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that
/// provides references to the intrinsic server objects
/// </param>
private void Enqueue(HttpContext context)
{
imageOperations.Enqueue(() => ProcessImage(context));
}

最佳答案

它看起来像你的 ProcessImage方法适用于 HttpContext ,这将是每次调用您的 HttpModule 的单个实例。 OnBeginAsync您的 HttpModule 会根据需要在每个 Web 请求中调用,并且您的委托(delegate)已经为您提供了执行异步操作的逻辑。这意味着,您不需要 4 个并发线程,因为您只有一个 context。无论如何,要处理的实例。而且我们不需要 ConcurrentQueue因为所有关于 context 的工作应该在请求-响应的生命周期内完成。

总而言之,你不需要ConcurrentQueue因为:

  1. 通过 HttpModule 的请求已经是并发的(来自 Web 主机架构)。
  2. 每个请求都处理一个 context实例。
  3. 您需要来自 ProcessImage 的工作于 context 完成从 OnEndAsync 回来之前.

相反,您只想开始 ProcessImage 的后台工作在OnBeginAsync方法,然后确保在您的 OnEndAsync 中完成工作方法。此外,由于所有更改都是直接在 context 上进行的实例(我假设,因为 ProcessImage 没有返回类型,它正在更新 context ),您不需要做任何进一步的工作来从您的处理中获取结果对象。

你可以放弃 ConcurrentQueue并简单地使用:

IAsyncResult OnBeginAsync(object sender, EventArgs e, 
AsyncCallback cb, object extraData)
{
HttpContext context = ((HttpApplication)sender).Context;
EnqueueDelegate enqueueDelegate = new EnqueueDelegate(ProcessImage);

return enqueueDelegate.BeginInvoke(context, cb, extraData);
}

public void OnEndAsync(IAsyncResult result)
{
// Ensure our ProcessImage has completed in the background.
while (!result.IsComplete)
{
System.Threading.Thread.Sleep(1);
}
}

您可以删除 ConcurrentQueue<Action> imageOperationsEnqueue你也可以重命名 EnqueueDelegate成为ProcessImageDelegate因为它现在可以直接使用该方法。

注意:可能是您的context尚未准备好 ProcessImageOnBeginAsync 的时候.如果是这样的话,你将不得不移动ProcessImage作为 OnEndAsync 内的简单同步调用.然而,也就是说,ProcessImage 确实有可能可以通过一些并发来改进。

我要说的另一个挑剔的观点是 hasAppStarted可以重命名 hasModuleInitialized减少歧义。

关于c# - 在 HttpModule 中正确使用 ConcurrentQueue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15530560/

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