翻译HoudiniEngine官方文档:Sessions

2024-09-06 23:18

本文主要是介绍翻译HoudiniEngine官方文档:Sessions,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

官方文档:《Houdini Engine 3.6: Sessions》

介绍

session的概念是在 Houdini Engine 2.x 中引入的。 在先前版本中,Houdini Engine 的动态链接库,也就是libHAPI,会直接链接到Houdini的核心组件,而宿主程序通常又链接到libHAPI。 这意味着 Houdini Engine 的实现是在宿主进程中运行的。

这一设计有两个主要问题:

  • 因为libHAPI在宿主进程中加载了核心的Houdini库,而这些库又有多个第三方依赖项。因此它们很可能与宿主应用程序自身的依赖项发生冲突
  • 每一个进程只能有一个Houdini场景。

在 Houdini Engine 3.x 中,我们仍支持这种“进程内”的形式——这对于简单的宿主程序可能仍旧是一个不错的选择。然而,我们还提供了一种新的 IPC(inter-process communication:进程间通信) 机制。这样,宿主应用程序可以运行多个session——在它自己的进程中或单独的进程中——以并行的方式或是在其他机器上(如果需要的话)。

每一个这样的session都用 HAPI_Session 来表示,大多数HAPI中的函数都需要它作为参数。

进程外(Out-of-process)

另一方面,如果你想利用 “IPC实现” 的优势,或者说你想以较低的开销轻松地在 “IPC实现” 与 “进程内实现” 做切换,你应该将你的应用链接到libHAPILlibHAPIL代表 Houdini Engine API Loader,它是一个充当 “楔子”(shim) 的库,它可以加载libHAPIlibHARC(我们的IPC客户端实现)、或者甚至是一个用户提供的动态库。

libHAPIL导出在HAPI.h中声明的函数。这些函数中的大多数都被重定向到一个动态链接实现的库(例如libHAPIlibHARC),而其他函数是用于加载库和创建session的特殊函数,并在libHAPIL本身中实现。

如果你将应用链接到libHAPIL,那么你必须在调用任何使用session作为参数的HAPI函数(包括HAPI_Initialize())之前,显式地创建一个session

比如说,HAPI_CreateInProcessSession() 动态加载libHAPI并在其输出参数中返回一个 “进程内session” 的单例。 请注意,在调用此函数之前,不会有任何Houdini库和依赖项在宿主进程中加载。 这可能有助于解决依赖关系问题。

你可以在调用HAPI_CreateInProcessSession()时传入 NULL 表示被创建的 “进程内session” 的单例。

如果你想使用我们的 “基于Thrift的IPC实现”,那么在创建session时,你可以:

  • 使用HAPI_CreateThriftSocketSession()(使用“TCP sockets”作为传输层)
  • 或者HAPI_CreateThriftNamedPipeSession()(在Windows系统上使用“named pipes”,在类Unix系统上使用“domain sockets”)

首次创建Thrift的session时,libHAPIL会加载libHARC,即客户端的动态库,为HAPI调用实现Thrift绑定。

你甚至可以实现自己定义的IPC客户端库,使用HAPI_BindCustomImplementation()将其绑定到HAPI_SessionType枚举中的自定义插槽之一,并使用HAPI_CreateCustomSession()创建基于此实现的session,并将创建session所需的参数作为原始指针传递。

最后,当session的工作结束了之后,可以使用HAPI_CloseSession()将其关闭。 在libHARC实现中,这将关闭客户端与服务器的连接。 如果在客户端的生存期内未使用HAPI_CloseSession()显式地关闭session,则在客户端进程终止时将自动关闭该session

使用“自动关闭”这个选项创建session时,关联的服务器进程将在最后一个session关闭时终止。 请注意,在非Windows系统上,必须在宿主应用程序中处理“SIGCHLD event”,以使服务器进程完全终止并返回 license。

请注意,session可以打开多个,实现的库也可以同时加载多个。

这是个简单的示例,展示了如何启动和连接一个 “进程外session”,以及如何初始化Houdini Engine API。

// HARS(Houdini-Engine API Remote Server)选项
HAPI_ThriftServerOptions serverOptions{ 0 };
serverOptions.autoClose = true;
serverOptions.timeoutMs = 3000.0f;
// 使用"hapi"名字的 Named Pipe 来创建我们的HARS服务器
// 如果你之前已经手动启动了 HARS,则可以忽略这个调用
if (HAPI_RESULT_SUCCESS != HAPI_StartThriftNamedPipeServer(&serverOptions, "hapi", nullptr))return false;
// 创建一个新的 HAPI session,它会使用刚才那个服务器
HAPI_Session session;
if (HAPI_RESULT_SUCCESS != HAPI_CreateThriftNamedPipeSession(&session, "hapi"))return false;
// 初始化 HAPI
HAPI_CookOptions cookOptions = HAPI_CookOptions_Create();
if (HAPI_RESULT_SUCCESS != HAPI_Initialize(&session,           // session:你正在与之交互的 session。如果是 NULL则表示使用默认的 “进程内session”&cookOptions,       // cook options:一个全局的 cook option,后续的cook默认都会用它。//			     每次cook都可以覆盖此设置,但是如果你选择在cook_on_load设置为true的情况下实例化 asset,则将使用这个选项。true,               // use_cooking_thread:是否使用一个不同的线程来cook,这允许异步cook和更大的栈尺寸。-1,                 // cooking_thread_stack_size:设置cook线程的栈的尺寸,单位为 byte。“-1”代表使用 Houdini的默认值。"",                 // houdini_environment_files:一串路径列表(在Windows上以“;”作为分隔符,在Linux和Mac上以“:”作为分隔符)。//							  这些文件后缀为 .env 的文件遵循Houdini用户偏好文件夹中的 houdini.env 文件的格式。//							  它们将会在默认的 houdini.env 文件之后应用,并会覆盖掉进程的环境变量的值//							  你可以使用它来在运行HoudiniEngine时强制为一个更严格的环境。详见:http://www.sidefx.com/docs/houdini/basics/config_envnullptr,            // otl_search_path:OTL 的搜索路径。nullptr,            // dso_search_path:通用的 DSO(自定义插件)的搜索路径。nullptr,            // image_dso_search_path:图像的 DSO(自定义插件)的搜索路径。nullptr     ))      // audio_dso_search_path:音频的 DSO(自定义插件)的搜索路径。
{return false
}

进程内(In-Process)

如果你对使用IPC不感兴趣,只想在进程内运行 Houdini Engine,则可以将宿主应用程序直接链接到libHAPI,并且在成功调用HAPI_Initialize()之前不需要调用任何其他函数。

libHAPI包含 Houdini Engine 功能实际的实现,以及与Houdini核心组件直接进行交互的接口,但不包含IPC机制的实现。

如果是从更早的 HAPI 1.x 代码库中移植,则只需向所有HAPI调用添加HAPI_Session指针参数。 使用“进程内”的方式时,这个额外的session指针参数将被忽略,因此你需要将其设置为 NULL 以获得一致性。

HARS (Houdini-Engine API Remote Server)

在客户端上使用libHARC(基于Thrift的IPC库)时,你需要启动服务器的可执行文件HARS,该文件在Houdini安装目录中。 HARS是具有简单命令行参数的控制台应用程序:

$ HARS -h
Allowed options:-h [ --help ]             显示此帮助信息-s [ --socket-port ] arg  服务器端口(如果使用TCP Socket Session)-n [ --named-pipe ] arg   pipe的名字(如果使用named pipe session)-a [ --auto-close ]       当所有客户端被关闭时,自动关闭服务器-r [ --ready-handle ] arg 服务器准备就绪时将设置的 Win32 Event 的句柄(Windows)服务器准备就绪时将发布的 POSIX named semaphore 的名称(Linux / macOS)(用于服务器自动启动)

HARS直接链接到libHAPI、核心的Houdini库、以及它们的依赖项。 因为基于 Thrift 的 IPC 是跨平台的,所以可以在不同平台上构建并运行主进程(使用libHAPILlibHARC)和服务器进程(HARS)。

你能通过“命令行”或者“管线脚本”以所需的选项来启动一个HARS进程。然后使用相应的session创建函数,在应用程序的C ++代码中建立与服务器的客户端连接。或者,你也可以在创建session之前,方便地使用函数HAPI_StartThriftSocketServer() 或HAPI_StartThriftNamedPipeServer() 从C++代码启动服务器。这些函数都会将程序阻塞,直到服务器发出准备好服务的信号为止。也就是说,一旦这些函数成功地返回了,就说明已经可以安全地创建session了。

请注意,HARS服务器当前仅支持单个客户端连接。 如果服务器已经与一个客户端连接了,那么当第二个客户端尝试连接时,第二个客户端就会阻塞,直到第一个连接关闭。

Houdini Engine Debugger

(译者注:在新版18.5中,此功能已经被 Houdini Engine SessionSync 功能替换)

多线程

使用libHARC基于 Thrift 的 RPC 实现时,一个宿主应用程序进程可以与多个HAPIsession进行交互,每个session都以其各自的Houdini状态代表其自己的HARS进程。 这为使用Houdini Engine的应用程序打开了新的多线程可能性。 当使用来自多个线程的多个session时,libHARC被设计为“线程安全”的。

对每个session的访问都受到互斥锁的保护,因此多线程可以安全地访问一个session。但事实上,仅使用一个session是无法真正实现“并行化”的。 在操作顺序有要求的情况下,客户端代码可能还需要在单个session上执行同步操作。 例如,在处理几何体时,设置几何体属性的顺序并不重要,重要的是HAPI_CommitGeo()需要在设置所有几何体属性之后调用。

另一方面,对于多个session,并行化成为可能,因为它们的Houdini上下文是完全独立的。 以下代码示例说明了如何通过独立的session进行操作,从而在异步任务之间并行地读写每个Tile的体数据。

class testharcSession
{
public:testharcSession(){mySession.type = HAPI_SESSION_MAX;mySession.id = 0;}virtual ~testharcSession(){if (mySession.type != HAPI_SESSION_MAX){HARC_TEST_SUCCESS(HAPI_IsSessionValid(&mySession));HARC_TEST_SUCCESS(HAPI_CloseSession(&mySession));HARC_TEST_ASSERT(HAPI_IsSessionValid(&mySession) == HAPI_RESULT_INVALID_SESSION);}}virtual void open() = 0;const HAPI_Session* get(){return &mySession;}
protected:HAPI_Session mySession;
};
class testharcSimpleAutoSession : public testharcSession
{
public:testharcSimpleAutoSession(const char* session_name_suffix,size_t task_id,const HAPI_ThriftServerOptions& server_options){std::ostringstream pipe_name_os;pipe_name_os << "/tmp/testharc_threading_"<< session_name_suffix << task_id << '_'
#ifdef WIN32<< GetCurrentProcessId();
#else<< getpid();
#endifmyPipeName = pipe_name_os.str();myServerOptions = server_options;myServerOptions.autoClose = true;}virtual ~testharcSimpleAutoSession(){if (mySession.type != HAPI_SESSION_MAX){HARC_TEST_SUCCESS(HAPI_IsInitialized(&mySession));HARC_TEST_SUCCESS(HAPI_Cleanup(&mySession));
#ifndef WIN32::unlink(myPipeName.c_str());
#endif}}virtual void open(){HARC_TEST_SUCCESS(HAPI_StartThriftNamedPipeServer(&myServerOptions, myPipeName.c_str(), nullptr));HARC_TEST_SUCCESS(HAPI_CreateThriftNamedPipeSession(&mySession,myPipeName.c_str()));HAPI_CookOptions cook_options = HAPI_CookOptions_Create();cook_options.splitGeosByGroup = false;HARC_TEST_SUCCESS(HAPI_Initialize(&mySession, &cook_options, true, -1,nullptr, nullptr, nullptr, nullptr, nullptr));}
private:HAPI_ThriftServerOptions    myServerOptions;std::string                 myPipeName;
};
class testharcCopyTileValues
{
public:testharcCopyTileValues(const HAPI_Session* dst_session,const HAPI_Session* src_session,HAPI_NodeId node_id,HAPI_PartId part_id,HAPI_NodeId input_node_id,const HAPI_VolumeTileInfo& tile_info,int tile_value_count): myDstSession(dst_session), mySrcSession(src_session), myNodeId(node_id), myPartId(part_id), myInputNodeId(input_node_id), myTileInfo(tile_info), myTileValueCount(tile_value_count){}void operator()(){// 分配 Tile 数据的 Bufferstd::vector<float> tile_values(static_cast<size_t>(myTileValueCount), -5.8f);// 获得颜色数据HARC_TEST_SUCCESS(HAPI_GetVolumeTileFloatData(mySrcSession,myNodeId, myPartId,-8.8f,&myTileInfo, &tile_values.front(), myTileValueCount));// 设置输入体数据上的颜色数据HARC_TEST_SUCCESS(HAPI_SetVolumeTileFloatData(myDstSession,myInputNodeId,0,&myTileInfo, &tile_values.front(), myTileValueCount));}
private:const HAPI_Session * myDstSession;const HAPI_Session * mySrcSession;HAPI_NodeId myNodeId;HAPI_PartId myPartId;HAPI_NodeId myInputNodeId;HAPI_VolumeTileInfo myTileInfo;int myTileValueCount;
};
void
testharcCopyVolume(std::shared_ptr<testharcSession> src_session,std::shared_ptr<testharcSession> dst_session
)
{src_session->open();// 从文件加载资产库HAPI_AssetLibraryId library_id = -1;HARC_TEST_SUCCESS(HAPI_LoadAssetLibraryFromFile(src_session->get(), "HAPI_Test_Volumes_HoudiniFogColor.otl",false, &library_id));HARC_TEST_ASSERT(library_id >= 0);// 实例化资产HAPI_NodeId node_id = -1;HARC_TEST_SUCCESS(HAPI_CreateNode(src_session->get(), -1, "Object/HAPI_Test_Volumes_HoudiniFogColor",nullptr, true, &node_id));HAPI_GeoInfo geo_info;HARC_TEST_SUCCESS(HAPI_GetDisplayGeoInfo(src_session->get(), node_id, &geo_info));// 获得 part 信息,第二个(也就是说索引号是1)part应该是红色体数据const HAPI_PartId part_id = 1;// 获得 part 信息HAPI_PartInfo part_info;HARC_TEST_SUCCESS(HAPI_GetPartInfo(src_session->get(), geo_info.nodeId, part_id, &part_info));// 获得 volume 信息HAPI_VolumeInfo volume_info;HARC_TEST_SUCCESS(HAPI_GetVolumeInfo(src_session->get(), geo_info.nodeId, part_id, &volume_info));HARC_TEST_ASSERT(volume_info.tupleSize == 1);HARC_TEST_ASSERT(!volume_info.hasTaper);dst_session->open();// 创建输入节点来接收体数据HAPI_NodeId input_node_id = -1;HARC_TEST_SUCCESS(HAPI_CreateInputNode(dst_session->get(), &input_node_id, "Input_Volume"));// 设置 part 信息HARC_TEST_SUCCESS(HAPI_SetPartInfo(dst_session->get(), input_node_id, 0, &part_info));// 设置 volume 信息HARC_TEST_SUCCESS(HAPI_SetVolumeInfo(dst_session->get(), input_node_id, 0, &volume_info));// 获得第一个体数据 TileHAPI_VolumeTileInfo tile_info;HARC_TEST_SUCCESS(HAPI_GetFirstVolumeTile(src_session->get(), geo_info.nodeId, part_id, &tile_info));HARC_TEST_ASSERT(tile_info.isValid);std::vector< std::future< void > > futures;const int tile_value_count =volume_info.tileSize *volume_info.tileSize *volume_info.tileSize *volume_info.tupleSize;while (tile_info.isValid){futures.push_back(std::async(std::launch::async,testharcCopyTileValues(dst_session->get(), src_session->get(),geo_info.nodeId, part_id, input_node_id,tile_info, tile_value_count)));// 获得下一个TileHARC_TEST_SUCCESS(HAPI_GetNextVolumeTile(src_session->get(),geo_info.nodeId, part_id,&tile_info));}for (auto & future : futures)future.get();// 提交体数据输入HARC_TEST_SUCCESS(HAPI_CommitGeo(dst_session->get(), input_node_id));// 对节点进行 cookHARC_TEST_SUCCESS(HAPI_CookNode(dst_session->get(), input_node_id, nullptr));HARC_TEST_ASSERT(testharcVerifyInputVolume_HoudiniVolume(dst_session->get(), input_node_id, 0));
}

最后,用于管理session的函数(session创建函数,HAPI_IsSessionValid()和HAPI_CloseSession())共享一个互斥锁。但是它们不会干扰并发调用的常规HAPI函数(除了HAPI_CloseSession(),它会使session无效,如果随后将其传递给HAPI函数将导致未定义的行为)。

你始终可以安全地调用HAPI_IsSessionValid()来确定session是否有效。

这篇关于翻译HoudiniEngine官方文档:Sessions的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1143397

相关文章

C#实现一键批量合并PDF文档

《C#实现一键批量合并PDF文档》这篇文章主要为大家详细介绍了如何使用C#实现一键批量合并PDF文档功能,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言效果展示功能实现1、添加文件2、文件分组(书签)3、定义页码范围4、自定义显示5、定义页面尺寸6、PDF批量合并7、其他方法

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

Python自动化处理PDF文档的操作完整指南

《Python自动化处理PDF文档的操作完整指南》在办公自动化中,PDF文档处理是一项常见需求,本文将介绍如何使用Python实现PDF文档的自动化处理,感兴趣的小伙伴可以跟随小编一起学习一下... 目录使用pymupdf读写PDF文件基本概念安装pymupdf提取文本内容提取图像添加水印使用pdfplum

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W

C#高效实现Word文档内容查找与替换的6种方法

《C#高效实现Word文档内容查找与替换的6种方法》在日常文档处理工作中,尤其是面对大型Word文档时,手动查找、替换文本往往既耗时又容易出错,本文整理了C#查找与替换Word内容的6种方法,大家可以... 目录环境准备方法一:查找文本并替换为新文本方法二:使用正则表达式查找并替换文本方法三:将文本替换为图

Python批量替换多个Word文档的多个关键字的方法

《Python批量替换多个Word文档的多个关键字的方法》有时,我们手头上有多个Excel或者Word文件,但是领导突然要求对某几个术语进行批量的修改,你是不是有要崩溃的感觉,所以本文给大家介绍了Py... 目录工具准备先梳理一下思路神奇代码来啦!代码详解激动人心的测试结语嘿,各位小伙伴们,大家好!有没有想

Python调用LibreOffice处理自动化文档的完整指南

《Python调用LibreOffice处理自动化文档的完整指南》在数字化转型的浪潮中,文档处理自动化已成为提升效率的关键,LibreOffice作为开源办公软件的佼佼者,其命令行功能结合Python... 目录引言一、环境搭建:三步构建自动化基石1. 安装LibreOffice与python2. 验证安装

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

flask库中sessions.py的使用小结

《flask库中sessions.py的使用小结》在Flask中Session是一种用于在不同请求之间存储用户数据的机制,Session默认是基于客户端Cookie的,但数据会经过加密签名,防止篡改,... 目录1. Flask Session 的基本使用(1) 启用 Session(2) 存储和读取 Se