使用线程和信号量
Using threads and semaphores
我有几千个文件,我使用函数提取一些信息,然后将信息输入数据库。从磁盘读取文件很快。提取数据很慢。更新数据库很快。我想在多个线程上执行此操作,以更好地利用 CPU。我设置了一个信号量,但没有看到预期的行为。我希望看到程序开始处理三个文件,然后完成一个文件,然后才开始另一个文件。一开始我看到不止三个文件同时开始处理,其中 none 个已经完成。
using System;
using System.Threading;
using System.IO;
using System.Collections.Generic;
namespace Threads
{
class Program
{
static Semaphore semaphore = new Semaphore(3, 3);
static Queue<string> queue = new Queue<string>();
public static void Main(string[] args)
{
string[] files = Directory.GetFiles(@"C:\MyFolder");
foreach (string file in files) {
queue.Enqueue(file);
}
while (queue.Count > 0) {
string fileName1 = NextFile();
semaphore.WaitOne();
Thread thread1 = new Thread(() => ProcessFile(fileName1));
thread1.Start();
semaphore.Release();
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
public static void ProcessFile(string fileName)
{
Console.WriteLine("Processing file " + fileName);
string value = ExtractData(fileName);
InsertInDatabase(value);
Console.WriteLine("Completed processing file " + fileName);
}
public static string NextFile()
{
string fileName = queue.Dequeue();
return fileName;
}
/// <summary>
/// This function takes a long time
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
static string ExtractData(string fileName)
{
Thread.Sleep(5000);
return "value";
}
static void InsertInDatabase(string value)
{
Thread.Sleep(100);
// do some work
}
}
}
使用信号量时,实际执行工作的线程应该等待,然后释放信号量。
这里主线程在等待信号量,然后在启动一个工作线程后立即释放。
while (queue.Count > 0) {
string fileName1 = NextFile();
semaphore.WaitOne();
Thread thread1 = new Thread(() => ProcessFile(fileName1));
thread1.Start();
semaphore.Release();
}
您应该将 sempahore.WaitOne()
移动到 ProcessFile
方法,因为它将转到实际使用资源的线程。
public static void ProcessFile(string fileName)
{
semaphore.WaitOne();
try
{
Console.WriteLine("Processing file " + fileName);
string value = ExtractData(fileName);
InsertInDatabase(value);
Console.WriteLine("Completed processing file " + fileName);
}
finally
{
// make sure the sempahore releases even if we encounter an error
semaphore.Release();
}
}
我有几千个文件,我使用函数提取一些信息,然后将信息输入数据库。从磁盘读取文件很快。提取数据很慢。更新数据库很快。我想在多个线程上执行此操作,以更好地利用 CPU。我设置了一个信号量,但没有看到预期的行为。我希望看到程序开始处理三个文件,然后完成一个文件,然后才开始另一个文件。一开始我看到不止三个文件同时开始处理,其中 none 个已经完成。
using System;
using System.Threading;
using System.IO;
using System.Collections.Generic;
namespace Threads
{
class Program
{
static Semaphore semaphore = new Semaphore(3, 3);
static Queue<string> queue = new Queue<string>();
public static void Main(string[] args)
{
string[] files = Directory.GetFiles(@"C:\MyFolder");
foreach (string file in files) {
queue.Enqueue(file);
}
while (queue.Count > 0) {
string fileName1 = NextFile();
semaphore.WaitOne();
Thread thread1 = new Thread(() => ProcessFile(fileName1));
thread1.Start();
semaphore.Release();
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
public static void ProcessFile(string fileName)
{
Console.WriteLine("Processing file " + fileName);
string value = ExtractData(fileName);
InsertInDatabase(value);
Console.WriteLine("Completed processing file " + fileName);
}
public static string NextFile()
{
string fileName = queue.Dequeue();
return fileName;
}
/// <summary>
/// This function takes a long time
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
static string ExtractData(string fileName)
{
Thread.Sleep(5000);
return "value";
}
static void InsertInDatabase(string value)
{
Thread.Sleep(100);
// do some work
}
}
}
使用信号量时,实际执行工作的线程应该等待,然后释放信号量。
这里主线程在等待信号量,然后在启动一个工作线程后立即释放。
while (queue.Count > 0) {
string fileName1 = NextFile();
semaphore.WaitOne();
Thread thread1 = new Thread(() => ProcessFile(fileName1));
thread1.Start();
semaphore.Release();
}
您应该将 sempahore.WaitOne()
移动到 ProcessFile
方法,因为它将转到实际使用资源的线程。
public static void ProcessFile(string fileName)
{
semaphore.WaitOne();
try
{
Console.WriteLine("Processing file " + fileName);
string value = ExtractData(fileName);
InsertInDatabase(value);
Console.WriteLine("Completed processing file " + fileName);
}
finally
{
// make sure the sempahore releases even if we encounter an error
semaphore.Release();
}
}