C#-线程池队列用户工作项使用

本文关键字:工作 用户 线程 队列 C#- | 更新日期: 2023-09-27 18:20:36

现在我正在使用以下代码添加排队线程。我不喜欢它。我的同事也不会,因为他们对C#不是很了解。当然,我只想将要在新线程中执行的方法排队。

private static void doStuff(string parameter)
{
    // does stuff
}
// call (a)
ThreadPool.QueueUserWorkItem(a => doStuff("hello world"));
// call (b)
ThreadPool.QueueUserWorkItem(delegate { doStuff("hello world"); });

那么ThreadPool.QueueUserWorkItem还有其他使用变体吗

最好再打一个1线球。如果可能,使用Func<>Action<>


编辑:从答案和评论中得到(b),我已经更喜欢了。

C#-线程池队列用户工作项使用

我不完全确定您在寻找什么样的语法,但如果您不喜欢示例中未使用的a,为什么不使用Task呢?

Task.Run(() => doStuff("hello world"));

它看起来并没有好到哪里去,但至少它没有一个未使用的标识符。

注:Task.Run()是.Net 4.5或更高版本。如果你正在使用.Net 4,你必须做:

Task.Factory.StartNew(() => doStuff("hello world"));

它没有那么短。

以上两者都使用线程池。

如果你真的必须避免使用lambda,你可以使用匿名委托(@nowhewhomustnotbename已经提到过):

Task.Run(delegate { doStuff("Hello, World!"); });

但这有什么意义呢?它的可读性要差得多!

问题的答案取决于您如何设计应用程序。你把它放在一个共同的项目中吗?你不想让一个简单的操作开销过大。

但是,您可以为ThreadPool QueueUserItem创建一个通用调用,用于接收params、1 param、2 param等。这很好,而不是发送一个简单的字符串并受到限制。

这就是如何用WaitCallback:实现参数QueueUserItem

ThreadPool.QueueUserWorkItem(
  new WaitCallback(delegate(object state)
  { YourMethod(Param1, Param2, Param3); }), null);

取自带有线程池的C#执行方法(带参数)

以及一些想法链接:
http://msdn.microsoft.com/en-us/library/4yd16hza.aspx
.NET中的通用线程池
委托之间的差异。BeginInvoke和使用C#中的ThreadPool线程

这个怎么样?

class Program
{
    static void Main(string[] args)
    {
        ThreadPool.QueueUserWorkItem(MyWork, "text");
        Console.ReadKey();
    }
    private static void MyWork(object argument)
    {
        Console.WriteLine("Argument: " + argument);
    }
}

或者,如果你不想有签名限制,并且有一种简单的方法将方法放在线程上,你可以这样做。对于那些返回值和不返回值并且最多有6个参数的方法,如果我没有错的话,它需要定义12个重载。它需要更多的前期工作,但使用起来更简单。

class Program
{
    static void Main(string[] args)
    {
        var myClass = new MyClass();
        myClass.DoWork();
        Console.ReadKey();
    }
}
public static class ObjectThreadExtension
{
    public static void OnThread(this object @object, Action action)
    {
        ThreadPool.QueueUserWorkItem(state =>
        {
            action();
        });
    }
    public static void OnThread<T>(this object @object, Action<T> action, T argument)
    {
        ThreadPool.QueueUserWorkItem(state =>
        {
            action(argument);
        });
    }
}
public class MyClass
{
    private void MyMethod()
    {
        Console.WriteLine("I could have been put on a thread if you like.");
    }
    private void MySecondMethod(string argument)
    {
        Console.WriteLine(argument);
    }
    public void DoWork()
    {
        this.OnThread(MyMethod);
        this.OnThread(MySecondMethod, "My argument");
    }
}

我认为使用框架而不是"反对它";。我并不是说其他答案是错误的,它们都是围绕基本方法调用包装器,有时会在出现问题时抑制堆栈。

看看我的扩展方法

public static class SMTPLoggerExtensionMethods
{
    class MailData
    {
        public MailData(EMailRoles role, string subject,string body, bool isHtml)
        {
            this.Roles = role;
            this.Subject = subject;
            this.Body = body;
            this.IsHtml = isHtml;
        }
        public EMailRoles Roles { get;  }
        public string Subject { get;  }
        public string Body { get; }
        public bool IsHtml { get; }
    }
    /// <summary>
    /// Send an email to all users defined in the email configuration of the IFireWall using a non-blocking method
    /// </summary>
    /// <param name="fireWall">The firewall instance</param>
    /// <param name="roles">The roles that are to be send the email</param>
    /// <param name="subject">the subject for the email</param>
    /// <param name="body">the email body</param>
    /// <param name="isHtml">indicating the email is HTML formated </param>
    public static void SendEmail(this IFireWall fireWall, EMailRoles roles, string subject, string body, bool isHtml)
    {
        var state = new MailData(roles, subject, body, isHtml);
        System.Threading.ThreadPool.QueueUserWorkItem(PSendMail, state);
    }
    private static void PSendMail(object? state)
    {
        if (state is MailData mail)
        {
            var smtp = DIContainer.GetDefaultInstanceOrNull<SMTPMailLogger>();
            smtp?.Enqueue(mail.Roles, mail.Subject, mail.Body, mail.IsHtml);
        }
    }
}

不能保证电子邮件会被发送,错误也不会被填充回呼叫者,但作为一种向给定组的所有用户发送电子邮件的非阻塞方法。。。为什么不呢?对于您的用例来说,向给定组中的所有用户发送电子邮件时没有错误,响应速度也不慢可能很好。

然后我会调用如下控制器示例所示的扩展方法。

没有阻塞,在我的情况下,如果我们错过了一封电子邮件,也没有压力,因为日志中包含用户体验良好的错误。。。。真正在看日志的人;-)

[BlockDuration(seconds: 60, sliding: true, doubleDurationPerIncident: true)]
public class HomeController : Controller
{
    private readonly IFireWall _fireWall;
    private readonly IPageRequest _page;
    private ILatLongRepository _latLongRepository;
    public HomeController(IFireWall fireWall, IPageRequest page, ILatLongRepository latLongRepository)
    {
        _page = page;
        _fireWall = fireWall;
        _latLongRepository = latLongRepository;
    }

    [GeoIgnore(maxRequest: 5)]
    [Ignore(skip: FireWallGuardModules.RejectPenetrationAttempts
                | FireWallGuardModules.RejectRepeatViolations
                | FireWallGuardModules.RejectWrongUserType
        , skipCount: 5)]
    public IActionResult Blocked(BlockingReason id)
    {
        //call the extension method here
        _fireWall.SendEmail(roles: Walter.Web.FireWall.Destinations.Email.EMailRoles.SecurityRelevant | Walter.Web.FireWall.Destinations.Email.EMailRoles.FireWallAdministrationViolations
            , subject: $"Access to {_page.OriginalUrl} rejected for user in {_latLongRepository.QueryMapLocation(_page.IPAddress)}"
            , body: MailUtils.MakeMailBodyForBlcokedUser(page: _page)
            , isHtml: true
            );
        if (_page.User.AsFirewallUser().UserType.HasFlag(UserTypes.IsMalicious))
        {
            return View("_Malicious", id);
        }
        return View(id);
   }
}