代码之家  ›  专栏  ›  技术社区  ›  Aik

调用以并行化foreach时出现问题

  •  4
  • Aik  · 技术社区  · 14 年前

    但调用方法有时会冻结。

    private void button1_Click(object sender, EventArgs e)
    {
        DateTime start = DateTime.Now;
        pforeach();
        Text = (DateTime.Now - start).ToString();
    }
    
    
    private void pforeach()
    {
        int[] intArray = new int[60];
        int totalcount = intArray.Length;
        object lck = new object();
        System.Threading.Tasks.Parallel.ForEach<int, int>(intArray,
        () => 0,
        (x, loop, count) =>
        {
            int value = 0;
            System.Threading.Thread.Sleep(100);
            count++;
            value = (int)(100f / (float)totalcount * (float)count);
    
            Set(value);
            return count;
        },
        (x) =>
        {
    
        });
    }
    
    private void Set(int i)
    {
        if (this.InvokeRequired)
        {
            var result = Invoke(new Action<int>(Set), i);
        }
        else
            progressBar1.Value = i;
    }
    

    有时它会毫无问题地过去,但通常会冻结 var result = Invoke (new Action <int> (Set), i) .

    非常感谢。

    2 回复  |  直到 14 年前
        1
  •  5
  •   Stephen Cleary    14 年前

    你的问题是 Invoke Task TaskScheduler )两者都要求UI线程处理其消息循环。然而,事实并非如此。它仍在等待 Parallel.ForEach

    并行循环 任务

    private TaskScheduler ui;
    private void button1_Click(object sender, EventArgs e) 
    {
        ui = TaskScheduler.FromCurrentSynchronizationContext();
        DateTime start = DateTime.Now;
        Task.Factory.StartNew(pforeach)
            .ContinueWith(task =>
            {
                task.Wait(); // Ensure errors are propogated to the UI thread.
                Text = (DateTime.Now - start).ToString(); 
            }, ui);
    } 
    
    private void pforeach() 
    { 
        int[] intArray = new int[60]; 
        int totalcount = intArray.Length; 
        object lck = new object(); 
        System.Threading.Tasks.Parallel.ForEach<int, int>(intArray, 
        () => 0, 
        (x, loop, count) => 
        { 
            int value = 0; 
            System.Threading.Thread.Sleep(100); 
            count++; 
            value = (int)(100f / (float)totalcount * (float)count); 
    
            Task.Factory.StartNew(
                () => Set(value),
                CancellationToken.None,
                TaskCreationOptions.None,
                ui).Wait();
            return count; 
        }, 
        (x) => 
        { 
    
        }); 
    } 
    
    private void Set(int i) 
    { 
        progressBar1.Value = i; 
    } 
    
        2
  •  1
  •   James Black    14 年前

    我正在研究我是如何做到这一点的,这一变化可能会帮助您:

    在我的构造函数中,我有这样一行:

    TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        private void changeProgressBar()
        {
            (new Task(() =>
            {
                mainProgressBar.Value++;
                mainProgressTextField.Text = mainProgressBar.Value + " of " + mainProgressBar.Maximum;
            })).Start(uiScheduler);
        }
    

    这样就不需要使用Invoke Task 方法,然后它可以解决你的问题。

    我想这些都在里面 System.Threading.Tasks;