TFuture和 TPromise是生产者-消费者模式的经典实现,让一个线程生产结果,另一个线程消费结果。下面详细说明它们的配对使用方式:
基本使用模式

1. 基础示例:简单值传递

 

1. 基础示例:简单值传递

 
#include "Async/Async.h"

// 创建Promise
TPromise<int32> Promise;

// 从Promise获取Future
TFuture<int32> Future = Promise.GetFuture();

// 在另一个线程设置值
Async(EAsyncExecution::Thread, [Promise = MoveTemp(Promise)]() mutable {
    FPlatformProcess::Sleep(1.0f); // 模拟耗时操作
    int32 Result = 100;
    Promise.SetValue(Result);  // 设置结果
    // 或 Promise.SetValue(42);
});

// 在主线程获取结果
if (Future.WaitFor(FTimespan::FromSeconds(2))) {  // 等待2秒
    int32 Value = Future.Get();  // 获取值
    UE_LOG(LogTemp, Log, TEXT("Result: %d"), Value);
} else {
    UE_LOG(LogTemp, Warning, TEXT("Timeout!"));
}

2. 完整工作流

 
// 创建一个计算服务
class FCalculationService {
public:
    TFuture<int32> CalculateSum(const TArray<int32>& Numbers) {
        TPromise<int32> Promise = TPromise<int32>::Create();
        TFuture<int32> Future = Promise.GetFuture();
        
        // 将Promise的所有权转移给工作线程
        Async(EAsyncExecution::ThreadPool, 
            [Numbers, Promise = MoveTemp(Promise)]() mutable {
                int32 Sum = 0;
                for (int32 Num : Numbers) {
                    Sum += Num;
                }
                // 计算完成,设置结果
                Promise.SetValue(Sum);
            }
        );
        
        return Future;  // 返回Future给调用者
    }
};

// 使用
FCalculationService Service;
TFuture<int32> SumFuture = Service.CalculateSum({1, 2, 3, 4, 5});

// 可以继续做其他事情...

if (SumFuture.IsReady()) {
    int32 Result = SumFuture.Get();
    UE_LOG(LogTemp, Log, TEXT("Sum: %d"), Result);
}

高级用法

3. 处理复杂对象

 
// 处理自定义结构
struct FProcessedData {
    TArray<uint8> Data;
    FString Metadata;
    double ProcessingTime;
};

TFuture<FProcessedData> ProcessFile(const FString& FilePath) {
    TPromise<FProcessedData> Promise = TPromise<FProcessedData>::Create();
    TFuture<FProcessedData> Future = Promise.GetFuture();
    
    Async(EAsyncExecution::Thread, 
        [FilePath, Promise = MoveTemp(Promise)]() mutable {
            FProcessedData Result;
            
            // 模拟处理
            TArray<uint8> FileData = LoadFile(FilePath);
            Result.Data = CompressData(FileData);
            Result.Metadata = GenerateMetadata(FilePath);
            Result.ProcessingTime = FPlatformTime::Seconds();
            
            // 设置结果
            Promise.SetValue(MoveTemp(Result));
        }
    );
    
    return Future;
}

4. 错误处理

 
TFuture<UTexture2D*> LoadTextureAsync(const FString& TexturePath) {
    TPromise<UTexture2D*> Promise = TPromise<UTexture2D*>::Create();
    TFuture<UTexture2D*> Future = Promise.GetFuture();
    
    Async(EAsyncExecution::Thread, 
        [TexturePath, Promise = MoveTemp(Promise)]() mutable {
            try {
                UTexture2D* Texture = LoadTextureFromDisk(TexturePath);
                if (!Texture) {
                    throw std::runtime_error("Failed to load texture");
                }
                Promise.SetValue(Texture);
            } catch (const std::exception& e) {
                // Future.Get() 会抛出异常
                // 或使用 SetValue 传递错误状态
                Promise.SetValue(nullptr);
            }
        }
    );
    
    return Future;
}

5. 网络请求包装

 
// 将HTTP请求包装为Future
TFuture<FHttpResponsePtr> MakeHttpRequest(const FString& URL) {
    TPromise<FHttpResponsePtr> Promise = TPromise<FHttpResponsePtr>::Create();
    TFuture<FHttpResponsePtr> Future = Promise.GetFuture();
    
    TSharedRef<IHttpRequest> Request = FHttpModule::Get().CreateRequest();
    Request->SetURL(URL);
    Request->OnProcessRequestComplete().BindLambda(
        [Promise = MoveTemp(Promise)](
            FHttpRequestPtr Request, 
            FHttpResponsePtr Response, 
            bool bSuccess) mutable {
            if (bSuccess) {
                Promise.SetValue(Response);
            } else {
                Promise.SetValue(nullptr);
            }
        }
    );
    Request->ProcessRequest();
    
    return Future;
}
posted on 2026-02-04 19:36  偷懒的阿贤  阅读(1)  评论(0)    收藏  举报