我想知道这个场景是否是线程安全的,是否存在我目前没有看到的问题:
从ASP.net控制器我从非静态类调用非静态方法(此类在另一个项目中,类被注入到控制器中).
这个方法(非静态的)做了一些工作,并调用一些其他静态方法传递userId
最后,静态方法做了一些工作(需要userId)
我相信这种方法是线程安全的,并且如果两个用户同时调用此方法,那么一切都将正确完成(让我们说同样的纳秒).我是正确还是完全错误?如果我错了,在ASP.net项目中使用静态方法的正确方法是什么?
编辑
这是代码:)
这是来自控制器的调用:
await _workoutService.DeleteWorkoutByIdAsync(AzureRedisFeedsConnectionMultiplexer.GetRedisDatabase(),AzureRedisLeaderBoardConnectionMultiplexer.GetRedisDatabase(), workout.Id, userId);
Run Code Online (Sandbox Code Playgroud)
这里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;
}
Run Code Online (Sandbox Code Playgroud)
您可以注意到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);
}
Run Code Online (Sandbox Code Playgroud)
这里是静态方法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));
}
}
Run Code Online (Sandbox Code Playgroud)
“线程安全”不是一个独立的术语。线程安全面临着什么?您期望在这里进行什么样的并发修改?
这里我们从几个方面来看:
DatabaseContext. 这看起来像一个 SQL 数据库,并且这些数据库往往是线程“安全”的,但这到底意味着什么取决于所讨论的数据库。例如,您要删除一行Trenings,如果其他线程也删除同一行,您可能会收到(安全)并发冲突异常。根据隔离级别,即使对于“Trenings”的其他某些突变,您也可能会遇到并发冲突异常。在最坏的情况下,这意味着一个请求失败,但数据库本身不会损坏。但是,您的代码对于其正在执行的操作来说似乎过于复杂。如果您希望能够长期保持这一点,我建议您大幅简化它。
ref参数(这里没有必要)。 ToString()尽可能避免。 绝对要避免一些令人讨厌的技巧,例如Contains检查键是否相等。您希望代码在发生意外情况时中断,因为“一瘸一拐”的代码几乎不可能调试(并且您将编写错误)。