ue4的多线程如何实现
ue4的多线程如何实现
讲道理
一般要使用多线程技术的,就是该功能点费时,并且降低效率,阻碍体验。
就ue4来说,多线程一般用于后台的计算,信号的发送,检测等。
比如,通过开启一个线程进行心跳检测,确认码的发送。
实例
那么,在ue4中我们如何实现多线程呢?我们通过一个计算质数的功能来掩饰有无单线程的差别。
创建c++工程
新建一个FunctionLibrary
在functionlibrary里编写三个函数,并且在cpp里面加以实现
/////////=================.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyBlueprintFunctionLibrary.generated.h"
/**
*
*/
UCLASS()
class MULTITHREADTEST_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "MultiThreadTest")
static void MultiThreadDo(int32 MaxPrime);//多线程处理,参数用于计算质数
UFUNCTION(BlueprintCallable, Category = "MultiThreadTest")
static void SingleThreadDo(int32 MaxPrime);//单线程处理,参数用于计算质数
static void Do(int32 MaxPrime);//处理调用,参数用于计算质数
};
/////////=================.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyBlueprintFunctionLibrary.h"
void UMyBlueprintFunctionLibrary::MultiThreadDo(int32 MaxPrime)
{
}
void UMyBlueprintFunctionLibrary::SingleThreadDo(int32 MaxPrime)
{
}
void UMyBlueprintFunctionLibrary::Do(int32 MaxPrime)
{
}
再创建一个空类
/////////=================.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class MULTITHREADTEST_API MyTaskClass
{
public:
MyTaskClass();
~MyTaskClass();
};
/////////=================.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyTaskClass.h"
MyTaskClass::MyTaskClass()
{
}
MyTaskClass::~MyTaskClass()
{
}
- 改写该类
/////////=================.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include <Runtime/Core/Public/Async/AsyncWork.h>
/**
*
*/
class MULTITHREADTEST_API MyTaskClass :public FNonAbandonableTask
{
public:
MyTaskClass();
~MyTaskClass();
//该类必须要有的一个函数,用于生成标注生成线程的信息
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(PrimeCalculationAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
}
void DoWork();//该方法继承与父类,在生成线程时会调用该方法进行执行任务
int32 MaxPrime;//由于该方法不是静态方法,所以必须在生成该类的时候赋给我们需要的进行计算的值
MyTaskClass(int32 MaxPrime);//补充一个构造函数用于赋值
};
/////////=================.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyTaskClass.h"
MyTaskClass::MyTaskClass()
{
}
MyTaskClass::~MyTaskClass()
{
}
void MyTaskClass::DoWork()
{
}
MyTaskClass::MyTaskClass(int32 MaxPrime)
{
this->MaxPrime = MaxPrime;
}
- 对functionlibrary进行补充,只在cpp文件进行改动
/////////=================.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyBlueprintFunctionLibrary.h"
#include "MyTaskClass.h"
void UMyBlueprintFunctionLibrary::MultiThreadDo(int32 MaxPrime)
{
/*开启线程*/
auto task = new FAutoDeleteAsyncTask<MyTaskClass>(MaxPrime);
if (task)
task->StartBackgroundTask();
//通过阅读源码得知,该方式启用task,会自动新建一个线程,并且调用该类的dowork函数
}
void UMyBlueprintFunctionLibrary::SingleThreadDo(int32 MaxPrime)
{
Do(MaxPrime);
}
void UMyBlueprintFunctionLibrary::Do(int32 MaxPrime)
{
//Calculating the prime numbers...
for (int32 i = 1; i <= MaxPrime; i++)
{
bool isPrime = true;
for (int32 j = 2; j <= i / 2; j++)
{
if (FMath::Fmod(i, j) == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
GLog->Log("Prime number #" + FString::FromInt(i) + ": " + FString::FromInt(i));
}
}
- 对task进行补充,只在cpp文件进行改动
/////////=================.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyTaskClass.h"
#include "MyBlueprintFunctionLibrary.h"
MyTaskClass::MyTaskClass()
{
}
MyTaskClass::~MyTaskClass()
{
}
void MyTaskClass::DoWork()
{
UMyBlueprintFunctionLibrary::Do(MaxPrime);
}
MyTaskClass::MyTaskClass(int32 MaxPrime)
{
this->MaxPrime = MaxPrime;
对该项目在vs 上进行生成
创建测试用例
- 接下来我们回到ue编辑器,新建一个actor
- 查找函数
- 把该actor拖入场景中,点击play,可以在日志里面看到计算结果的打印信息,也可以从界面上明显感受到两种方式的效果差。
结论
测试表明两者的差别主要是没有开启线程的程序,在程序运行时占用主线程导致主线程卡顿