[英]Calling static async methods from ASP.net project
I'm wondering will this scenario be thread safe and are there issues that I'm not currently seeing: 我想知道这个场景是否是线程安全的,是否存在我目前没有看到的问题:
From ASP.net controller I call non-static method from non-static class (this class is in another project, and class is injected into controller). 从ASP.net控制器我从非静态类调用非静态方法(此类在另一个项目中,类被注入到控制器中)。
This method (which is non-static) does some work and calls some other static method passing it userId 这个方法(非静态的)做了一些工作,并调用一些其他静态方法传递userId
Finally static method does some work (for which userId is needed) 最后,静态方法做了一些工作(需要userId)
I believe this approach is thread safe, and that everything will be done properly if two users call this method at the same time (let's say in same nanosecond). 我相信这种方法是线程安全的,并且如果两个用户同时调用此方法,那么一切都将正确完成(让我们说同样的纳秒)。 Am I correct or completely wrong ?
我是正确还是完全错误? If I am wrong what would be correct way of using static methods within ASP.net project ?
如果我错了,在ASP.net项目中使用静态方法的正确方法是什么?
EDIT 编辑
Here is code :) 这是代码:)
This is call from the controller: 这是来自控制器的调用:
await _workoutService.DeleteWorkoutByIdAsync(AzureRedisFeedsConnectionMultiplexer.GetRedisDatabase(),AzureRedisLeaderBoardConnectionMultiplexer.GetRedisDatabase(), workout.Id, userId);
Here how DeleteWorkoutByIdAsync looks like: 这里DeleteWorkoutByIdAsync的样子如下:
public async Task<bool> DeleteWorkoutByIdAsync(IDatabase redisDb,IDatabase redisLeaderBoardDb, Guid id, string userId)
{
using (var databaseContext = new DatabaseContext())
{
var workout = await databaseContext.Trenings.FindAsync(id);
if (workout == null)
{
return false;
}
databaseContext.Trenings.Remove(workout);
await databaseContext.SaveChangesAsync();
await RedisFeedService.StaticDeleteFeedItemFromFeedsAsync(redisDb,redisLeaderBoardDb, userId, workout.TreningId.ToString());
}
return true;
}
As you can notice DeleteWorkoutByIdAsync calls static method StaticDeleteFeedItemFromFeedsAsync which looks like this: 您可以注意到DeleteWorkoutByIdAsync调用静态方法StaticDeleteFeedItemFromFeedsAsync,如下所示:
public static async Task StaticDeleteFeedItemFromFeedsAsync(IDatabase redisDb,IDatabase redisLeaderBoardDd, string userId, string workoutId)
{
var deleteTasks = new List<Task>();
var feedAllRedisVals = await redisDb.ListRangeAsync("FeedAllWorkouts:" + userId);
DeleteItemFromRedisAsync(redisDb, feedAllRedisVals, "FeedAllWorkouts:" + userId, workoutId, ref deleteTasks);
await Task.WhenAll(deleteTasks);
}
And here is static method DeleteItemFromRedisAsync which is called in StaticDeleteFeedItemFromFeedsAsync: 这里是静态方法DeleteItemFromRedisAsync,它在StaticDeleteFeedItemFromFeedsAsync中调用:
private static void DeleteItemFromRedisAsync(IDatabase redisDb, RedisValue [] feed, string redisKey, string workoutId, ref List<Task> deleteTasks)
{
var itemToRemove = "";
foreach (var f in feed)
{
if (f.ToString().Contains(workoutId))
{
itemToRemove = f;
break;
}
}
if (!string.IsNullOrEmpty(itemToRemove))
{
deleteTasks.Add(redisDb.ListRemoveAsync(redisKey, itemToRemove));
}
}
Note: this answer was posted before the OP amended their question to add their code, revealing that this is actually a question of whether async/await is thread-safe. 注意:这个答案是在OP修改他们的问题之前发布的,以添加他们的代码,这表明这实际上是async / await是否是线程安全的问题。
Static methods are not a problem in and of themselves. 静态方法本身不是问题。 If a static method is self-contained and manages to do its job using local variables only, then it is perfectly thread safe.
如果静态方法是自包含的并且仅使用局部变量设法完成其工作,那么它是完全线程安全的。
Problems arise if the static method is not self-contained, (delegates to thread-unsafe code,) or if it manipulates static state in a non-thread safe fashion, ie accesses static variables for both read and write outside of a lock()
clause. 如果静态方法不是自包含的(委托给线程不安全的代码),或者它以非线程安全的方式操作静态状态,即在
lock()
外部读取和写入静态变量,则会出现问题条款。
For example, int.parse()
and int.tryParse()
are static, but perfectly thread safe. 例如,
int.parse()
和int.tryParse()
是静态的,但完全是线程安全的。 Imagine the horror if they were not thread-safe. 想象一下如果他们不是线程安全的恐怖。
"Thread safe" isn't a standalone term. “线程安全”不是一个独立的术语。 Thread Safe in the the face of what?
线程安全在面对什么? What kind of concurrent modifications are you expecting here?
你期待什么样的并发修改?
Let's look at a few aspects here: 我们来看几个方面:
DatabaseContext
. DatabaseContext
。 This looks like an sql database, and those tend to be thread "safe", but what exactly that means depends on the database in question. Trenings
row, and if some other thread also removes the same row, you're likely to get a (safe) concurrency violation exception. Trenings
行,如果某个其他线程也删除了同一行,您可能会遇到(安全)并发冲突异常。 And depending on isolation level, you may get concurrency violation exceptions even for other certain mutations of "Trenings". However, your code seems excessively complicated for what it's doing. 但是,您的代码似乎过于复杂。 I'd recommend you simplify it dramatically if you want to be able to maintain this in the long run.
如果您希望能够长期保持这一点,我建议您大大简化它。
ref
parameters unless you really know what you're doing (and it's not necessary here). ref
参数(这里没有必要)。 ToString()
where possible. ToString()
。 Definitely avoid nasty tricks like Contains
to check for key equality. Contains
这样令人讨厌的技巧来检查密钥相等。 You want your code to break when something unexpected happens, because code that "limps along" can be virtually impossible to debug (and you will write bugs). what you are doing here is synchronizing on a list (deleteTasks). 你在这里做的是在列表上同步(deleteTasks)。 If you do this i would recommend 1 of 2 things.
如果你这样做我会推荐2件事中的一件。
1) Either use thread safe collections https://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx 1)使用线程安全集合https://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx
2) Let your DeleteItemFromRedisAsync return a task and await it. 2)让您的DeleteItemFromRedisAsync返回一个任务并等待它。
Although i think in this particular case i don't see any issues as soon as you refactor it and DeleteItemFromRedisAsync can get called multiple times in parallel then you will have issues. 虽然我认为在这种特殊情况下,一旦你重构它就不会发现任何问题,并且DeleteItemFromRedisAsync可以多次并行调用,那么你就会遇到问题。 The reason being is that if multiple threads can modify your list of deleteTasks then you are not longer guaranteed you collect them all ( https://msdn.microsoft.com/en-us/library/dd997373(v=vs.110).aspx if 2 threads do an "Add"/Add-to-the-end in a non-thread safe way at the same time then 1 of them is lost) so you might have missed a task when waiting for all of them to finish.
原因是如果多个线程可以修改你的deleteTasks列表,那么你不再保证你全部收集它们( https://msdn.microsoft.com/en-us/library/dd997373(v=vs.110)。 aspx如果2个线程同时以非线程安全的方式执行“添加”/“添加到结束”,则其中1个丢失)因此您可能在等待所有任务完成时错过了任务。
Also i would avoid mixing paradigms. 我也会避免混合范式。 Either use async/await or keep track of a collection of tasks and let methods add to that list.
使用async / await或跟踪任务集合并让方法添加到该列表。 don't do both.
不要两者都做。 This will help the maintainability of your code in the long run.
从长远来看,这将有助于代码的可维护性。 (note, threads can still return a task, you collect those and then wait for all of them. but then the collecting method is responsible for any threading issues instead of it being hidden in the method that is being called)
(注意,线程仍然可以返回一个任务,你收集它们然后等待它们全部。但是收集方法负责任何线程问题,而不是隐藏在被调用的方法中)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.