UE4 的 异步怎么实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tianxiaojie_blog/article/details/84297371

原理

异步与多线程到底是怎么区分呢?江湖传闻,异步是目的,多线程是实现这个目的的方法。
那么,具体在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进行测试更能出现效果差
    在这里插入图片描述

结论

测试表明两者的差别主要是在与在加载资源的时候没有异步的加载方式出现了断续阻塞

扫描二维码关注公众号,回复: 4161535 查看本文章

猜你喜欢

转载自blog.csdn.net/tianxiaojie_blog/article/details/84297371