现在我正在使用以下代码添加排队线程。我不喜欢它。我的同事也不会,因为他们对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),我已经更喜欢了。
我不完全确定您在寻找什么样的语法,但如果您不喜欢示例中未使用的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);
}
}