wpf 如何让一定数量的线程一直运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15181675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:49:41  来源:igfitidea点击:

How to make certain number of threads running all the time

c#wpfmultithreadingthreadpoolmultitasking

提问by MonsterMMORPG

Ok here my question. I want to start threads until a certain number. Lets say 100. So it will start starting threads and check continuously number of running threads. When the maximum number reached it will stop starting new threads. But with a proper checking interval or completed thread will signal and it will start new thread.

好的,我的问题。我想开始线程直到某个数量。让我们说 100。所以它会开始启动线程并不断检查正在运行的线程数。当达到最大数量时,它将停止启动新线程。但是如果有适当的检查间隔或已完成的线程将发出信号,它将启动新线程。

With this way, i will always have certain number of running threads.

通过这种方式,我将始终拥有一定数量的运行线程。

I managed this with using sleep and permanent while. So i keep checking total running thread count with a given interval and if thread is completed, dispose it and start a new one.

我通过使用 sleep 和 Permanent while 来解决这个问题。所以我一直在检查给定时间间隔内的总运行线程数,如果线程完成,则处理它并开始一个新的。

But my solution is not coming me as a proper way. I suppose it would be better if the completed thread would signal and then checker would start a new one if we are below of the maximum number of threads threshold.

但是我的解决方案并不是以适当的方式出现。我想如果已完成的线程会发出信号,然后如果我们低于最大线程数阈值,则检查器将启动一个新线程会更好。

I saw many threadpool examples but most of them not contains any queued pooling with maximum amount of running threads. What i mean is, they just keep starting threads until they are done. But lets say i have 500k urls to harvest. I can not just start all of them in a for loop with thread pool.

我看到了许多线程池示例,但其中大多数不包含任何具有最大运行线程数量的排队池。我的意思是,他们只是继续启动线程,直到完成。但是可以说我有 50 万个网址要收集。我不能只是在带有线程池的 for 循环中启动所有这些。

platform is c# 4.5 WPF application

平台是 c# 4.5 WPF 应用程序

And here below is my solution. Actually i am looking for a better one. Not improving this one.

下面是我的解决方案。其实我正在寻找一个更好的。不改进这个。

private void Button_Click_4(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        startCrawler();
    });
}

void startCrawler()
{
    int irMaximumThreadcount = 100;
    List<Task> lstStartedThreads = new List<Task>();
    while (true)
    {
        for (int i = 0; i < lstStartedThreads.Count; i++)
        {
            if (lstStartedThreads[i].IsCompleted == true)
            {
                lstStartedThreads[i].Dispose();
                lstStartedThreads.RemoveAt(i);
            }
        }

        if (lstStartedThreads.Count < irMaximumThreadcount)
        {
            var vrTask = Task.Factory.StartNew(() =>
            {
                func_myTask();
            });
            lstStartedThreads.Add(vrTask);
        }

        System.Threading.Thread.Sleep(50);
    }
}

void func_myTask()
{

}

采纳答案by Felix

Personally I would use PLINQfor this, and specifically the WithDegreeOfParallelismmethod which limits the number of concurrent executions to the passed in value.

我个人会为此使用PLINQ,特别是WithDegreeOfParallelism方法,该方法将并发执行的数量限制为传入的值。

private IEnumerable<Action> InfiniteFunctions()
{
    while(true)
    {
        yield return func_myTask;
    }
}

private void Button_Click_4(object sender, RoutedEventArgs e)
{
    int irMaximumThreadcount = 100;
    InfiniteFunctions()
        .AsParallel()
        .WithDegreeOfParallelism(irMaximumThreadcount)
        .ForAll(f => f());
}

EDIT: Actually reading the documentation it seems that irMaximumThreadCount can only be a max of 64 so watch out for that.

编辑:实际上阅读文档似乎 irMaximumThreadCount 最多只能是 64,所以要注意这一点。

EDIT 2: Ok, had a better look and it seems Parallel.ForEachtakes a ParallelOptionsparameter which includes a MaxDegreeOfParallelismproperty that isn't limited - Check it out. So your code might be like:

编辑 2:好的,有一个更好的外观,它似乎Parallel.ForEach需要一个ParallelOptions参数,其中包含一个MaxDegreeOfParallelism不受限制的属性 -检查一下。所以你的代码可能是这样的:

private void CrawlWebsite(string url)
{
    //Implementation here
}

private void Button_Click_4(object sender, RoutedEventArgs e)
{
    var options = new ParallelOptions() 
    { 
        MaxDegreeOfParallelism = 2000 
    };

    Parallel.ForEach(massiveListOfUrls, options, CrawlWebsite);
}

回答by pescolino

You are mixing up tasks with threads. A task is not a thread. There is no guarantee that each task will have it's own thread.

您正在将任务与线程混淆。任务不是线程。不能保证每个任务都有自己的线程

Actually the TPL (Task Parallel Library) is some kind of queue. This means you can just create and start tasks for each Funcor Actionobject you have. There is no easy way to control the number of threadsthat are actually created.

实际上,TPL(任务并行库)是某种队列。这意味着您可以为您拥有的每个FuncAction对象创建和启动任务。没有简单的方法来控制实际创建的线程数

However, you can create many tasks with little overhead because the TPL will enqueue them and apply further logic to balance the work over the threads of the thread pool.

但是,您可以用很少的开销创建许多任务,因为 TPL 会将它们排入队列并应用进一步的逻辑来平衡线程池线程上的工作。

If some tasks need to be executed one after the other you can use Task.ContinueWithto enqueue them. It is also possible to start new tasks with Task.Factory.ContinueWhenAnyor Task.Factory.ContinueWhenAll.

如果某些任务需要一个接一个地执行,您可以使用Task.ContinueWith它们来排队。也可以使用Task.Factory.ContinueWhenAny或开始新任务Task.Factory.ContinueWhenAll

This is also the clue to how you can control the number of parallel tasks you want to create: Just create the desired number of tasks and enqueue the remaining tasks with ContinueWhenAny. Each time a task ends the next will be started.

这也是您如何控制要创建的并行任务数量的线索:只需创建所需数量的任务并使用ContinueWhenAny. 每次任务结束时,下一个将开始。

Again: the TPL will balance the work among the threads in the thread pool. What you need to consider anyway is the use of other resources like disk I/O or internet connection. Having a lot of tasks that try to use the same resources concurrently can drastically slow down your program.

再次:TPL 将平衡线程池中线程之间的工作。无论如何,您需要考虑的是使用其他资源,例如磁盘 I/O 或 Internet 连接。有许多尝试同时使用相同资源的任务会大大减慢您的程序速度。

回答by Despertar

.NET 4.0 introduced several collections with built-in concurrency management which should be ideal for this situation. A blocking collection will be more effecient then sleeping in a while loop. You then just spawn x threads that read from the blocking queue.

.NET 4.0 引入了几个带有内置并发管理的集合,这应该是这种情况的理想选择。阻塞收集将比在 while 循环中休眠更有效。然后,您只需生成 x 个从阻塞队列中读取的线程。

BlockingCollection<string> queue = new BlockingCollection<string>(listOfUrls);

for (int x=0; x < MaxThreads; x++)
{
    Task.Factory.StartNew(() => 
    {
        while (true)
        {
            string url = queue.Take(); // blocks until url is available
            // process url;
        }
    }, TaskCreationOptions.LongRunning);
}

You mark the task as long running so it will create it's own thread instead of using the thread pool. If you need first in first out, you can pass in a ConcurrentQueue<T>to the blocking collection constructor. http://msdn.microsoft.com/en-us/library/dd287085.aspx

您将任务标记为长时间运行,因此它将创建自己的线程而不是使用线程池。如果您需要先进先出,您可以将 a 传递ConcurrentQueue<T>给阻塞集合构造函数。http://msdn.microsoft.com/en-us/library/dd287085.aspx

回答by yaniv maymon

you can manage yourself the Task/Thread pool and wait for any Thread to be done and start a new one right away.

您可以管理自己的任务/线程池并等待任何线程完成并立即启动一个新线程。

MAX_THREAD_ALLOWED = 100;
List<Task> tasks = new List<Task>();
for (int i = 0; i < 1000; i++)
{
    tasks.Add(Task.Run(() => { Foo(i); }));
    if (i == MAX_THREAD_ALLOWED)
    {
        Task.WaitAny(tasks.ToArray());
        MAX_THREAD_ALLOWED++;
    }
}

回答by dotNET

Not an exact answer, but I think this may guide you in the correct direction.

不是一个确切的答案,但我认为这可能会引导您朝着正确的方向前进。

First, take a look at Thread.Join, especially the simple example given at the bottom of this page. This approach is superior to Thread.Sleep() and more suitable for your purpose. I'm thinking on the lines of *Join*ing the "manager" thread instead of *Sleep*ing.

首先,看看Thread.Join,尤其是本页底部给出的简单示例。这种方法优于 Thread.Sleep() 并且更适合您的目的。我正在考虑 * Join*ing the "manager" thread 而不是 * Sleep*ing 的行。

The second option that may or may not suit your purpose, is the new Taskslibrary. Since you're using the latest version of the framework, this option is available, but then I guess you cannot control the actual number of threads created by the Tasks library. It automatically chooses that value based on the underlying scheduler. However, there's an option named ParallelOptions.MaxDegreeOfParallelismthat sounds interesting.

可能适合也可能不适合您目的的第二个选项是新Tasks库。由于您使用的是最新版本的框架,因此可以使用此选项,但我猜您无法控制由 Tasks 库创建的实际线程数。它会根据底层调度程序自动选择该值。但是,有一个名为ParallelOptions.MaxDegreeOfParallelism的选项听起来很有趣。