Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Code-WHappy opened this issue Sep 24, 2021 · 11 comments
Assignees

Comments

@Code-WHappy
Copy link

问题类型:其它

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

如题
image

image

@heliqi
Copy link
Collaborator

heliqi commented Sep 26, 2021

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

@Code-WHappy
Copy link
Author

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

@xingyun8
Copy link

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

@ximitiejiang
Copy link

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

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

@Code-WHappy
Copy link
Author

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

@Code-WHappy
Copy link
Author

image
这是最终定位到的错误

@heliqi
Copy link
Collaborator

heliqi commented Oct 19, 2021

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

@ximitiejiang

@heliqi
Copy link
Collaborator

heliqi commented Oct 19, 2021

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

@Code-WHappy
Copy link
Author

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

@heliqi
Copy link
Collaborator

heliqi commented Oct 21, 2021

你看错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;

@sommour
Copy link

sommour commented Jan 14, 2023

是否有初始化两个实例(比如初始化两个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的网络,导致同时访问的时候冲突。
用线程池并不能解决我的需求:
第一,我用多线程是为了加快处理速度
第二,我各个线程的模型不尽相同
这个如何解决?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants