一个较长的调用会导致所有并行循环暂停或阻塞

问题描述 投票:0回答:1

我正在 Parallel.ForEach 中调用 VB 6.0 dll,并期望所有调用同时启动,或者根据我的 PC 核心或线程池中的线程可用性至少启动其中 2 个调用

VB6 动态链接库

Public Function DoJunk(ByVal counter As Long, ByVal data As String) As Integer
    Dim i As Long
    Dim j As Long
    Dim s As String

    Dim fno As Integer
    fno = FreeFile
    Open "E:\JunkVB6Dll\" & data & ".txt" For Output Access Write As #fno
    Print #fno, "Starting loop with counter = " & counter
    For i = 0 To counter
        Print #fno, "counting " & i
    Next

    Close #fno
    DoJunk = 1
End Function

计数器从调用者处传递来控制调用的执行时间,并且正在写入文件以使其成为基于 IO 的进程。

C# 调用者

private void ReportProgress(int value)
{
    progressBar.Value = value;
    //progressBar.Value++;
}

private void button1_Click(object sender, EventArgs e)
{
    progressBar.Value = 0;
    counter = 0;
    Stopwatch watch = new Stopwatch();
    watch.Start();

    //var range = Enumerable.Range(0, 100);
    var range = Enumerable.Range(0, 20);

    bool finished = false;


    Task.Factory.StartNew(() =>
    {
        Parallel.ForEach(range, i =>
        {
            #region COM CALL
            JunkProject.JunkClass junk = new JunkProject.JunkClass();
            try
            {
                Random rnd = new Random();
                int dice = rnd.Next(10, 40);

                int val = 0;
                if (i == 2)
                    val = junk.DoJunk(9000000, i.ToString());
                else
                    val = junk.DoJunk(dice * 10000, i.ToString());
                System.Diagnostics.Debug.Print(junk.GetHashCode().ToString());

                if (val == 1)
                {
                    Interlocked.Increment(ref counter);
                    progressBar.Invoke((Action)delegate { ReportProgress(counter); });
                }
                junk = null;
            }
            catch (Exception excep)
            {
                i = i;
            }
            finally { junk = null; }
            #endregion
        });
    }).ContinueWith(t =>
    {
        watch.Stop();
        MessageBox.Show(watch.ElapsedMilliseconds.ToString());
    });
}

此线路拨打特定电话的时间比其他线路长。

val = junk.DoJunk(9000000, i.ToString());

这里第二个进程导致 Parallel.ForEach 内的所有调用停止,即除非第二个调用完成,否则不会创建其他文件。

这是预期的行为还是我做错了什么?

c# parallel-processing vb6 task-parallel-library parallel.foreach
1个回答
0
投票

正如 @John Wu 建议您可以创建 AppDomain 以允许 COM 在不同的 App Domain 上运行,我相信您可以像这样运行并行。

        Parallel.ForEach(range, i =>
        {
            AppDomain otherDomain = AppDomain.CreateDomain(i.ToString());
            otherDomain.DoCallBack(delegate
            {
                //Your COM call
            });
        });

编辑

对..我不知道如何在 VB6.0 类上设置可序列化。您可以尝试其他方法(通过引用封送对象)。注意:我还没有实际测试过这个,但我想知道这是否有效。

        Parallel.ForEach(range, i =>
        {
            AppDomain otherDomain = AppDomain.CreateDomain(i.ToString());
            var comCall = (ComCall) otherDomain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, typeof(ComCall).ToString());
            comCall.Run();
            AppDomain.Unload(otherDomain);
        });

和班级

public class ComCall : MarshalByRefObject
{
    public void Run()
    {
        //Your COM Call
    }
}

这里还有有关该主题的其他参考。

https://www.codeproject.com/Articles/14791/NET-Remoting-with-an-easy-example

© www.soinside.com 2019 - 2024. All rights reserved.