PaddleX icon indicating copy to clipboard operation
PaddleX copied to clipboard

C# 两个线程不同时调用同一个模型推理报错,第一个线程用后,第二个线程无法使用?

Open Code-WHappy opened this issue 3 years ago • 11 comments

问题类型:其它

PaddleX版本
您使用的PaddleX版本 2.0.0 问题描述

如题 image

image

Code-WHappy avatar Sep 24 '21 13:09 Code-WHappy

是否有初始化两个实例(比如初始化两个model, 一个线程使用一个model实例)? 多线程情况下,如果只有一个推理实例,一次只有一个线程能调用该实例(不能有多个线程访问同一个实例)。

heliqi avatar Sep 26 '21 07:09 heliqi

两个线程一个model,但是线程1调用时,线程2不用。不会出现冲突的问题。有办法解决这个问题吗?不然调试起来太麻烦。因为我们自动运行是一个线程,调试是一个线程

Code-WHappy avatar Sep 26 '21 15:09 Code-WHappy

您好,请问您这个问题解决了吗?我也遇到同样的问题。

xingyun8 avatar Sep 29 '21 02:09 xingyun8

@heliqi 按这个说法,意思是每个model得绑定到一个固定线程去吗?Code-WHappy的应用场景其实已经是单线程访问了,只不过是多个线程分时访问同一个模型,如果这样无法支持,就只能理解为一个model得绑定到一个线程了。

但这样就太方便了,多个线程分时访问的需求太多了,难道没有解决方案吗?

ximitiejiang avatar Oct 13 '21 14:10 ximitiejiang

还没有解决,官方还没给出解决方案

Code-WHappy avatar Oct 19 '21 02:10 Code-WHappy

image 这是最终定位到的错误

Code-WHappy avatar Oct 19 '21 02:10 Code-WHappy

  1. 可以分时调用,必须要加锁,保证多个线程不能同时访问同一个实例
  2. 需要使用线程池或者让线程while住,一直保持存在(也就是线程id一直不变)。线程不能不断创建销毁,否则会引发底层cuda问题

@ximitiejiang

heliqi avatar Oct 19 '21 02:10 heliqi

推荐使用这个pr里的线程池:https://github.com/PaddlePaddle/PaddleX/pull/1179 对c++的dll接口进行封装,线程池使用参照multi_thread_infer2.cpp。 c#端调用初始化函数初始化model和线程池,推理时只需要调用submit函数(也可再封装这个接口)提交多线程任务即可

heliqi avatar Oct 19 '21 02:10 heliqi

我看了下你们这个multi_thread_infer2.cpp,这是推理的时候多线程同时推理,然后再合并结果。我们需要的是,一个推理一个线程即可,但是需要在线程ID变化的情况下也能用。也就是说线程1调用后,线程2在调用也可以

Code-WHappy avatar Oct 21 '21 02:10 Code-WHappy

你看错demo了吧? multi_thread_infer2.cpp这个例子,你改成只初始化model1, 然后调用下面的语句不就是你想要的两次调用么?我怀疑你看到的是multi_thread_infer.cpp的例子,这个针对batch的,所以才会合并结果。 auto future1 = pool.submit(infer, model1, ref(imgs), &results1, 1); auto future2 = pool.submit(infer, model1, ref(imgs), &results2, 1); future1.get(); std::cout << "result1:" << results1[0] << std::endl;

future2.get(); std::cout << "result1:" << results2[0] << std::endl;

heliqi avatar Oct 21 '21 06:10 heliqi

是否有初始化两个实例(比如初始化两个model, 一个线程使用一个model实例)? 多线程情况下,如果只有一个推理实例,一次只有一个线程能调用该实例(不能有多个线程访问同一个实例)。

你好,我最近用多个线程调用不同的模型,但是还是会出现线程冲突的情况,我把model_infer.dll更改名字都不行。也已经实例化了多个model。引用代码如下: class Classify { [DllImport("model_infer.dll", EntryPoint = "InitModel")] // Model unified initialization method: need yml、pdmodel、pdiparams public static extern IntPtr InitModel(string model_filename, string params_filename, string cfg_file, bool use_gpu);

    [DllImport("model_infer.dll", EntryPoint = "Cls_ModelPredict")]  // PaddleClas Model reasoning method
    public static extern void Cls_ModelPredict(IntPtr model, IntPtr img, int W, int H, int C, ref float score, ref byte category, ref int category_id);

    [DllImport("model_infer.dll", EntryPoint = "DestructModel")]  // Segmentation, detection, identification model destruction method
    public static extern void DestructModel(IntPtr model);
}

推测model_infer.dll会引用paddle_inference.dll的网络,导致同时访问的时候冲突。 用线程池并不能解决我的需求: 第一,我用多线程是为了加快处理速度 第二,我各个线程的模型不尽相同 这个如何解决?

sommour avatar Jan 14 '23 09:01 sommour