项目作者: dmitry007

项目描述 :
A tiny Delphi library (Delphi 10 or higher) that exposes Task and Task objects similar to those in .Net
高级语言: Pascal
项目地址: git://github.com/dmitry007/AsyncAwait.git
创建时间: 2019-12-15T04:32:11Z
项目社区:https://github.com/dmitry007/AsyncAwait

开源协议:MIT License

下载


AsyncAwait

This library (Delphi 10 or higher) exposes loose equivalents of the Task and Task objects in .Net that use COM infrastructure (IContextCallback.ContextCallback) to synchronize continuation calls on the main or any arbitrary thread. The same API is used by async/await in C# and co_await in VC++.
The library works in both exe and dll projects and (unlike TThread.Synchornize) does not rely on periodic calls to CheckSynchronize.

The source code is licensed under the MIT license.

To use this library, add AsyncAwait to the uses clause; you can then create code like the following:

  1. procedure TForm1.btnFibonacciClick(Sender: TObject);
  2. var
  3. seed: UInt64;
  4. begin
  5. seed := Random(MaxInt);
  6. lblResult.Caption := Format('Calculating Fibonacci number for %d. Please wait...', [seed]);
  7. TTask<UInt64>.Async(
  8. //timeconsuming call on a secondary thread
  9. function : UInt64
  10. begin
  11. Result := Fibonacci(seed);
  12. end,
  13. //update the UI on the main thread
  14. procedure(task : ITask<UInt64>; Value : UInt64)
  15. begin
  16. if task.Status = TTaskStatus.RanToCompletion
  17. then lblResult.Caption := Format('Fibonacci number for %d is %d', [seed, Value])
  18. else if task.Status = TTaskStatus.Faulted
  19. then lblResult.Caption := Format('Error calculating Fibonacci number: %s', [task.Exception.Message])
  20. end,
  21. //tell to continue on the main thread -
  22. //don't need to specify this parameter as it defaults to true anyway
  23. true
  24. );
  25. end;

You can also specify a particular synchronization context even if you start a new task on a secondary thread:

  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3. t : ITask<integer>;
  4. syncContext : ISynchronizationContext;
  5. begin
  6. syncContext := TSynchronizationContext.Current;
  7. t := TTask<integer>.Async(
  8. //async function
  9. function() : integer
  10. var
  11. delay : integer;
  12. begin
  13. delay := Random(10000);
  14. sleep(delay);
  15. Result := delay;
  16. //run another task
  17. //start it explicitly since we need to configure the
  18. //synchornization context (main thread) first
  19. //before the continuation code has a chance to run
  20. TTask.Create(
  21. procedure()
  22. begin
  23. sleep(2000);
  24. end
  25. ).
  26. ContinueWith(
  27. procedure(task : ITask)
  28. begin
  29. ShowMessage('Done second task');
  30. end,
  31. //use the sync context from the main thread since we are showing a window
  32. syncContext
  33. ).
  34. //now start the task after we configured it
  35. Start;
  36. end,
  37. //continue with
  38. //it is guaranteed to run on the calling thread (this main thread)
  39. //since continueOnCapturedContext parameter defaults to true
  40. procedure(task : ITask<integer>; Value : integer )
  41. begin
  42. if task.Status = TTaskStatus.RanToCompletion
  43. then ShowMessage(Format('All done after sleeping for %d seconds', [task.Value div 1000]))
  44. else if task.Status = TTaskStatus.Faulted
  45. then ShowMessage(Format('Task faulted. Exception type = %s: %s', [task.Exception.ClassName, task.Exception.Message]))
  46. end,
  47. //continue on the main thread - don't need to specify this parameter as it defaults to true
  48. true
  49. );
  50. if t.Wait(2000)
  51. then ShowMessage(Format('Done after waiting for less than 2 seconds. Task returned %d', [t.Value]))
  52. else ShowMessage('Still not done after waiting for 2 seconds');
  53. end;