我有一個看起來像這樣一個簡單的Web API方法:共享資源和異步的Web API調用
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
TaskManager.Run
是decalared這樣的:
public async Task Run(int id)
我期待它返回「任務被啓動「消息後立即TaskManager.Run(taskId)
但請求繼續同步運行。
但如果更換電話TaskManager.Run(taskId)
有:
Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(100)));
然後異步運行。
所以我認爲這與TaskManager
和主線程共享的資源有關。共享資源可以鎖定執行嗎?
我正在使用溫莎城堡。一個WindsorContainer
容器在Web API項目中聲明。 TaskManager在其內部使用BaseTaskRunner類。在BaseTaskRunner
中聲明瞭另外一個WindsorContainer
。 Web API的容器對所有組件使用LifeStyle.PerWebRequest
。 BaseTaskRunner
的容器使用LifeStyle.Singleton
(不確定它是否正確LifeStyle)。可以通過DdContext或其他在這兩個容器中聲明的類來鎖定該調用嗎?
UPD: 我不想等待TaskManager.Run完成。但是會發生什麼情況是,return語句仍然等待TaskManager.Run完成(即使沒有在TaskManager.Run上等待語句)。 換句話說,它不會不管我怎麼叫TaskManager.Run:
TaskManager.Run(taskId);
或
await TaskManager.Run(taskId);
它等待TaskManager.Run在這兩種情況下完成。
這裏是任務管理器的代碼:
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type, byte[] data = null, object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public async Task Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
Run(task, removeOnComplete);
}
public async Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public async Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
和一些其他類:
public class SpreadsheetImportTaskRunner : BaseTaskRunner
{
public IForecastSpreadsheetManager SpreadsheetManager { get; set; }
protected override void Execute()
{
SpreadsheetManager.ImportActuals(Task.Data);
}
protected override void Initialize()
{
base.Initialize();
SpreadsheetManager = _container.Resolve<IForecastSpreadsheetManager>();
}
}
BaseTaskRunner:
public class BaseTaskRunner
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
protected IWindsorContainer _container = new WindsorContainer();
protected BackgroundTask Task { get; set; }
public async Task Run(BackgroundTask task)
{
Initialize();
Task = task;
try
{
Execute();
}
catch (Exception ex)
{
SetError(ex.ToString());
}
}
protected virtual void Execute()
{
}
protected virtual void Initialize()
{
_container.Install(new TaskRunnerComponentsInstaller());
TaskRepository = _container.Resolve<IRepository<BackgroundTask>>();
}
}
我仍然認爲這是值得做的WindsorContainer以及在幾個不同的線程中解決的常見類。
這很混亂 - 你爲什麼需要等待TaskManager.CreateTask(taskType)而不是TaskManager.Run(taskId);?你試圖等待哪個操作? –
我需要等待TaskManager.CreateTask(taskType),因爲它重新調整了taskId。然後,我將taskId傳遞給Run方法,並希望它在後臺運行,同時將「任務已啓動」消息返回給用戶。 – user1016945
但爲什麼獲取taskId需要異步?你完全理解異步/等待模式(或一般的異步編程)嗎? –