1. 源代碼
AsyncWork.h
2. 多線程的使用
參考文檔:https://wiki.unrealengine.com/Using_AsyncTasks
當我們需要執行一個需要很長時間的任務時,放在主線程里會導致很卡,把此任務放到其他線程里則會好很多,此時多線程就可以起到關鍵的作用了。
在UE4里,我們可以使用FAsyncTask 或者FAutoDeleteAsyncTask。
使用FAsyncTask 時,我們需要手動停止或刪除任務;使用FAutoDeleteAsyncTask時,系統則會自動在任務結束后,刪除任務。
需要先建個繼承FNonAbandonableTask的類,如源碼中的例子:
class ExampleAutoDeleteAsyncTask : public FNonAbandonableTask { friend class FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>; int32 ExampleData; ExampleAutoDeleteAsyncTask(int32 InExampleData) : ExampleData(InExampleData) { } void DoWork() { ... do the work here } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(ExampleAutoDeleteAsyncTask, STATGROUP_ThreadPoolAsyncTasks); } };
然后具體調用就是:
void Example() { // start an example job (new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(5)->StartBackgroundTask(); // do an example job now, on this thread (new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(5)->StartSynchronousTask(); }
注意:StartBackgroundTask()是在另一個線程中執行此任務;StartSynchronousTask()是在當前線程中馬上執行此任務。
舉個例子:
.h: #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Kismet/KismetSystemLibrary.h" #include "MyActor.generated.h" UCLASS() class ASYNCWORKSTUDY_API AMyActor : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AMyActor(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; void TestAsync(FString Content); //多線程例子 void Example(); }; class ExampleAutoDeleteAsyncTask : public FNonAbandonableTask { friend class FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>; int32 ExampleData; UObject* Object; AMyActor* Target; ExampleAutoDeleteAsyncTask(int32 InExampleData, UObject* InObject, AMyActor* InTarget) : ExampleData(InExampleData), Object(InObject), Target(InTarget) { } void DoWork() { UKismetSystemLibrary::PrintString(Object, FString::FromInt(ExampleData)); //調用AMyactor的測試函數 if (Target) Target->TestAsync("Success"); } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(ExampleAutoDeleteAsyncTask, STATGROUP_ThreadPoolAsyncTasks); } }; .cpp: #include "MyActor.h" // Sets default values AMyActor::AMyActor() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; } // Called when the game starts or when spawned void AMyActor::BeginPlay() { Super::BeginPlay(); UKismetSystemLibrary::PrintString(this, "Hello"); Example(); } // Called every frame void AMyActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); } void AMyActor::TestAsync(FString Content) { UKismetSystemLibrary::PrintString(this, Content); } void AMyActor::Example() { //在其他線程里執行此任務 auto task = new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(10, GetWorld(), this); if (task) task->StartBackgroundTask(); //此任務會在當前線程中馬上開始。 auto task2= new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(15, GetWorld(), this); if (task2) task2->StartSynchronousTask(); }