当前位置:首页 > C#编程 > C#/.net框架 > 正文内容

使用Task.Factory.StartNew传递方法参数遇到的问题

Jorge2年前 (2022-05-09)C#/.net框架798

 

用下面的代码,会发生一个错误。

报的错误是FlowItemListP[i]的索引超范围,FlowItemListP.Count的值是3, 但是FlowItemListP[i]居然索引值是3

打死都想不到i怎么可能计数到3


C#
 for (int i = 0; i < FlowItemListP.Count; i++)
 {
    if (FlowItemListP[i].RunModeF == MotionFlowItemRunMode.串行)
    {
       serailTaskFactory.StartNew(() => FlowItemListP[i].Run(serialUnitCTS.Token),
       serialUnitCTS.Token, TaskCreationOptions.LongRunning, serialUnit); //FlowItemListP[i].Run, i, serialUnitCTS.Token);
    }
    else if (FlowItemListP[i].RunModeF == MotionFlowItemRunMode.并行)
    {
     parallelTaskFactory.StartNew(() => FlowItemListP[i].Run(parallelUnitCTS.Token), parallelUnitCTS.Token);
    }
 }


改成下面这样就可以了。

C#
 foreach(var m in FlowItemListP)
 {
                    if (m.RunModeF == MotionFlowItemRunMode.串行)
                    {
                        serailTaskFactory.StartNew(() => m.Run(serialUnitCTS.Token), serialUnitCTS.Token); 
                    }
                    else if (m.RunModeF == MotionFlowItemRunMode.并行)
                    {
                        parallelTaskFactory.StartNew(() => m.Run(parallelUnitCTS.Token), parallelUnitCTS.Token);
                    }
 }

之所以好了,是因为没有用到变量i

这个问题其实是lambda表达式的一个副作用。特别在循环里面用lambda表达式传递id变量要特别注意这个问题。

而这里之所以用lambda表达式,是为了StartNew()调用带参数的Run()函数。如果不用lambda表达式,还真不知道该怎么写。


恰好在网上看到一个人的提问。回答者也提醒了要注意的这个问题。

摘录如下:

----------------


我有以下代码:

C#
var task = Task.Factory.StartNew(CheckFiles, cancelCheckFile.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);private void CheckFiles(){  
   //Do stuff}

我现在想修改CheckFiles以接受和整数以及BlockingCollection引用

C#
private void CheckFiles(int InputID, BlockingCollection<string> BlockingDataCollection){
  //Do stuff}

我似乎找不到一个方法来开始这个任务,就像我上面所做的。

你能帮我吗?

谢谢

回复如下:

最好的选择是使用一个lambda表达式来关闭你想要显示的变量。

但是,在这种情况下要小心,特别是如果你在循环中调用这个。 (我提到这一点,因为你的变量是一个“ID”,这在这种情况下是常见的。)如果你在错误的范围内关闭变量,你可以得到一个错误。有关详细信息,请参阅Eric Lippert’s post on the subject.这通常需要进行临时:

C#
foreach(int id in myIdsToCheck){    int tempId = id; // Make a temporary here!
    Task.Factory.StartNew( () => CheckFiles(tempId, theBlockingCollection),
         cancelCheckFile.Token, 
         TaskCreationOptions.LongRunning, 
         TaskScheduler.Default);}

另外,如果你的代码和上面一样,你应该小心使用LongRunning提示 – 使用默认调度器,这将导致每个任务获得自己的专用线程,而不是使用ThreadPool。如果你创建了很多任务,这可能会产生负面影响,因为你不会得到ThreadPool的优势。它通常适用于一个单一的,长时间运行的任务(因此它的名称),而不是将被实现来处理集合的项目等。



--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!

扫描二维码推送至手机访问。

版权声明:本文由7点博客发布,如需转载请注明出处。

本文链接:http://6dot.cn/?id=80

标签: .NET.NET框架
分享给朋友:

“使用Task.Factory.StartNew传递方法参数遇到的问题” 的相关文章

C#中使用RegisterWindowMessage进行进程之间进行通讯

C#中使用RegisterWindowMessage进行进程之间进行通讯

注:大家都知道在window里,进程之间通讯可以用消息通讯。但是有个较冷门的知识就是RegisterWindowMessage。一般的sendmessage和postmessage是需要在窗体程序间进行通讯,你得知道对方窗口的句柄。这个句柄每次启动程序时是系统分配的,每次不一样。有了这个Regist...

细说进程、应用程序域与上下文之间的关系(三)—— 深入了解.NET上下文

细说进程、应用程序域与上下文之间的关系(三)—— 深入了解.NET上下文

目录一、进程的概念与作用二、应用程序域三、深入了解.NET上下文四、进程应用程序域与线程的关系三、深入了解.NET上下文3.1 .NET上下文的概念应用程序域是进程中承载程序集的逻辑分区,在应用程序域当中,存在更细粒度的用于承载.NET对象的实体,那就.NET上下文Context。所有的.NET对象...

细说进程、应用程序域与上下文之间的关系(二)—— 应用程序域

细说进程、应用程序域与上下文之间的关系(二)—— 应用程序域

目录一、进程的概念与作用二、应用程序域三、深入了解.NET上下文四、进程应用程序域与线程的关系 二、应用程序域使用.NET建立的可执行程序 *.exe,并没有直接承载到进程当中,而是承载到应用程序域(AppDomain)当中。应用程序域是.NET引入的一个新概念,它比进程所占用的资源要少,...

C#中CancellationToken和CancellationTokenSource用法

C#中CancellationToken和CancellationTokenSource用法

 继续谈一下异步中的任务取消机制CancellationToken和CancellationTokenSource。  之前做开发时,一直没注意这个东西,做了.net core之后,发现CancellationToken用的越来越平凡了。  这也难怪,原来.net framework使用异...

C# 外观模式(Facade)举一个例子

C# 外观模式(Facade)举一个例子

 有关外观模式见下面贴子,下面编写的一个例子。FundClass.csC#using System;using System.Collections.Generic;using System.Linq;using System.Text;namesp...

C# 外观模式(Facade)

C# 外观模式(Facade)

1. 外观模式简介  外观模式主要解决的问题:当有多个类要处理时,需要一个个类去调用,没有复用性和扩展性。外观模式将处理子类的过程封装成操作,简化客户端的调用过程。1.1 定义  外观模式(Facade)通过提供一个统一接口,来访问子系统的多个接口。  使用外观模式时,创建一个统一的类,用来包装子系...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。