我有一个方法,可以在观看视频时增加视频的视图。如果发布者的视频浏览量达到200次,我会给他发一封祝贺电子邮件,但是如果电子邮件发送延迟,我不希望用户等待该延迟来观看视频。我需要使视频加载不依赖于电子邮件发送。我使用了Task。运行和任务。工厂StartNew及其内部Parallel我没有任务/线程的经验,所以实现它的最佳方式是什么。
public async Task<ServiceResponse<ViewedVideoDto>> AddVideoView(int candidateVideoId)
{
var video = await _dbcontext.CandidateFiles.Include(x=>x.Candidate).ThenInclude(x=>x.User).FirstOrDefaultAsync(x => x.Id == candidateVideoId);
if (video is null)
{
return new ServiceResponse<ViewedVideoDto>().NotFound(nameof(Resource.VideoEmpty), Resource.VideoEmpty);
}
video.VideoViews += 1;
_dbcontext.Update(video);
await _dbcontext.SaveChangesAsync();
if (video.VideoViews == 200)
{
//Method 1
await Task.Run(() =>
_candidateEmailService.Achieved200VideoViews(video.Candidate.User.Email,
video.Candidate.User.FullName));
//Method 2
Task.Factory.StartNew(() => Parallel.Invoke(() =>
{
_candidateEmailService.Achieved200VideoViews(video.Candidate.User.Email,
video.Candidate.User.FullName);
}));
}
return new ServiceResponse<ViewedVideoDto>()
{
Data = new ViewedVideoDto()
{
VideoId = video.Id
}
};
}
public async Task Achieved200VideoViews(string receiverEmail, string fullName)
{
var candidateTemplate = EmailTemplate.Return(EmailTemplateConst.CanEmailTempFolder, EmailTemplateConst.CanAchieved200VideoViews,fullName);
var innoEmail = new InnoEmail()
{
Email = receiverEmail,
Subject = "Touchpoint after 200 views",
HtmlMessage = candidateTemplate
};
await _emailService.SendAsync(innoEmail);
public async Task<bool> SendAsync(Email email)
{
try
{
var apiKey = _configuration.GetSection("SENDGRID_API_KEY").GetSection("SecretKey").Value;
var Email = _configuration.GetSection("SENDGRID_API_KEY").GetSection("Email").Value;
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress(Email, "test"),
Subject = email.Subject,
PlainTextContent = null,
HtmlContent = email.HtmlMessage
};
msg.AddTo(new EmailAddress(email.Email));
var response = await client.SendEmailAsync(msg).ConfigureAwait(false);
response.StatusCode.ToString();
return true;
}
catch (System.Exception e)
{
return false;
}
}
方法1(await Task.Run(() =>
(将无法实现声明的目标,因为您正在等待基本上会暂停AddVideoView
执行直到Achieved200VideoViews
完成的结果。如果你想要即发即弃行为-取消等待。
基于Achieved200VideoViews
实现,基本上它只是发送邮件。我想说的是,哪一种更好并不重要,因为即发即弃方法都不够好:它们缺乏可观察性(例如,电子邮件发送可能因多种原因失败,或者在此过程中应用程序将重新启动(。
我建议并采用类似于事务发件箱模式的方法-向video
表或单独的表添加一个标志,该表将存储关于发送200个视图的通知的信息(类似于video.ToSend200ViewNotification
(,并在AddVideoView
中更新该信息,然后在一些后台作业处理程序中处理该表,例如使用托管服务或Hangfire或Quartz(或者添加标志Is200ViewNotificationSend
并处理视图>=200和Is200ViewNotificationSend
设置为false的所有视频(。
如果您同意即发即弃方法对同步操作的限制,则Task.Run
应优先(无await
(。正如文档中所写,TaskFactory.StartNew
更适合于更复杂的场景(而且它不具有任务意识,在"普通"情况下无法正确处理返回Task
的方法(:
从开始。NET Framework 4.5,
Task.Run
方法是启动计算绑定任务的推荐方法。仅当需要对长时间运行的、绑定计算的任务进行细粒度控制时,才使用StartNew
方法。这包括您想要控制以下内容的场景:
Task
创建选项。默认情况下,使用Task.Run
方法创建的任务是使用TaskCreationOptions.DenyChildAttach
选项创建的。要覆盖此行为或提供其他TaskCreationOptions
选项,请调用StartNew
重载- 参数传递。
Task.Run
方法的重载不允许将参数传递给任务委托。StartNew
方法的重载确实如此- 任务调度程序。
Task.Run
方法的重载使用默认的任务调度程序。要控制任务调度程序,请使用调度程序参数调用StartNew
过载。有关详细信息,请参阅TaskScheduler
但是由于您的Achieved200VideoViews
方法已经返回Task
,并且假设它是";真正异步";那么只要在调用上跳过await
就可以实现即发即弃功能(我想说这是优选的,因为它应该消耗更少的资源(:
_ = _candidateEmailService.Achieved200VideoViews(video.Candidate.User.Email,
video.Candidate.User.FullName);