1. 程式人生 > >UE4 的 非同步怎麼實現

UE4 的 非同步怎麼實現

UE4 的 非同步怎麼實現

原理

非同步與多執行緒到底是怎麼區分呢?江湖傳聞,非同步是目的,多執行緒是實現這個目的的方法。
那麼,具體在ue4裡面我們要去使用這兩個東西呢?

  • 非同步一般用於資源的載入,事件的延遲響應。呼叫了一個開啟非同步方法的函式之後,程式就會線上程池裡面尋找一些空閒執行緒對該函式進行處理。而該主執行緒繼續往下走,不會發生阻塞
  • 多執行緒一般用於訊號的傳送與接收,資料的計算等

例項

然後呢,非同步在ue4中如何實現?本例採用獲取資源的方式進行演示。

注:本例只演示如何編寫非同步程式碼,對於非同步對功能的優化效果,應該在體量較大較頻繁的操作中才可體現

建一個c++的ue4工程

在這裡插入圖片描述

新建c++類

在這裡插入圖片描述
在這裡插入圖片描述

/////////=================.h// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MyAsyncTaskActorComponent.generated.h" UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class ASYNCTEST_API UMyAsyncTaskActorComponent : public UActorComponent { GENERATED_BODY() public: // Sets default values for this component's properties UMyAsyncTaskActorComponent
(); protected: // Called when the game starts virtual void BeginPlay() override; public: // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType,FActorComponentTickFunction* ThisTickFunction) override; }; /////////=================.cpp // Fill out your copyright notice in the Description page of Project Settings. #include "MyAsyncTaskActorComponent.h" // Sets default values for this component's properties UMyAsyncTaskActorComponent::UMyAsyncTaskActorComponent() { // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // off to improve performance if you don't need them. PrimaryComponentTick.bCanEverTick = true; // ... } // Called when the game starts void UMyAsyncTaskActorComponent::BeginPlay() { Super::BeginPlay(); // ... } // Called every frame void UMyAsyncTaskActorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // ... }

進行程式碼補充


/////////=================.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include <Runtime/CoreUObject/Public/UObject/NoExportTypes.h>
#include <Runtime/Engine/Classes/Engine/StreamableManager.h>
#include <Runtime/Engine/Classes/Engine/AssetManager.h>
#include "MyAsyncTaskActorComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ASYNCTEST_API UMyAsyncTaskActorComponent : public UActorComponent
{
       GENERATED_BODY()
public:       
       // Sets default values for this component's properties
       UMyAsyncTaskActorComponent();
protected:
       // Called when the game starts
       virtual void BeginPlay() override;
public:       
       // Called every frame
       virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
       //=========定義委託,用於在專案中回撥接受回撥資料,這裡採用多播形式========
       DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMyReceiveDelegateEvent, bool, result, UObject *, obj);
       //======宣告委託======
       UPROPERTY(BlueprintAssignable, Category = "AsyncTask")
              FMyReceiveDelegateEvent MyReceiveDelegateEvent;
       //======定義一個資源路徑======
       FSoftObjectPath assetPath;
       //======呼叫委託函式的執行===========
       UFUNCTION(BlueprintCallable, Category = "AsyncLoadAsset")
              void GetObjectByPath(const FString path);
       //定義一個用於執行非同步的回撥函式
       void GetObject();
       //定義一個同步呼叫方法
       UFUNCTION(BlueprintCallable, Category = "AsyncLoadAsset")
              UObject * GetObjectAsset(const FString path);
};
/////////=================.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyAsyncTaskActorComponent.h"
// Sets default values for this component's properties
UMyAsyncTaskActorComponent::UMyAsyncTaskActorComponent()
{
       // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
       // off to improve performance if you don't need them.
       PrimaryComponentTick.bCanEverTick = true;
       // ...
}
// Called when the game starts
void UMyAsyncTaskActorComponent::BeginPlay()
{
       Super::BeginPlay();
       // ...
       
}
// Called every frame
void UMyAsyncTaskActorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
       Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
       // ...
}
void UMyAsyncTaskActorComponent::GetObjectByPath(const FString path)
{
       assetPath = FSoftObjectPath(path);//進行例項化資源路徑
       FStreamableManager& AssetLoader = UAssetManager::GetStreamableManager();
       AssetLoader.RequestAsyncLoad(assetPath, FStreamableDelegate::CreateUObject(this, &UMyAsyncTaskActorComponent::GetObject));
}
//=========注,小技巧,尋找到該路徑下資源,返回的是uobject,即所有的父類,然後再根據需要轉換回去
void UMyAsyncTaskActorComponent::GetObject()
{
       TSoftObjectPtr<UObject> ObjAsset(assetPath);
       UObject * obj = ObjAsset.Get();
       if (obj == nullptr)
       {
              MyReceiveDelegateEvent.Broadcast(false, nullptr);
              return;
       }
       MyReceiveDelegateEvent.Broadcast(true, obj);
}
UObject * UMyAsyncTaskActorComponent::GetObjectAsset(const FString path)
{
       UObject * obj = LoadObject<UObject >(NULL, *path);
       return obj;
}

建立例項

  • 生成一下程式碼然後回到編輯器中,新建一個普通actor在這裡插入圖片描述
  • 新增剛建立的actorcomponent在這裡插入圖片描述
  • 繫結代理事件並繫結事件在這裡插入圖片描述
    -在這裡插入圖片描述

測試程式碼

在這裡插入圖片描述

  • 拖入一個音訊檔案做測試用,並且複製該檔案的引用路徑,填充到測試程式碼裡面去
    在這裡插入圖片描述
    在這裡插入圖片描述

  • 對測試程式碼進行改進,用timer進行測試更能出現效果差
    在這裡插入圖片描述

結論

測試表明兩者的差別主要是在與在載入資源的時候沒有非同步的載入方式出現了斷續阻塞