C# 我试图在循环中调用一个方法。它应该在10秒内只被调用20次。我使用的信号量如下代码所示
通过使用下面的代码,首先,有些呼叫没有被拨打,比如说,在250个呼叫中,有238个呼叫被拨打,其余的没有。其次,我不确定这些呼叫是否以每10秒20个呼叫的速率拨打C# 我试图在循环中调用一个方法。它应该在10秒内只被调用20次。我使用的信号量如下代码所示,c#,multithreading,semaphore,C#,Multithreading,Semaphore,通过使用下面的代码,首先,有些呼叫没有被拨打,比如说,在250个呼叫中,有238个呼叫被拨打,其余的没有。其次,我不确定这些呼叫是否以每10秒20个呼叫的速率拨打 public List<ShowData> GetAllShowAndTheirCast() { ShowResponse allShows = GetAllShows(); ShowCasts showCast = new ShowCasts(); showCas
public List<ShowData> GetAllShowAndTheirCast()
{
ShowResponse allShows = GetAllShows();
ShowCasts showCast = new ShowCasts();
showCast.showCastList = new List<ShowData>();
using (Semaphore pool = new Semaphore(20, 20))
{
for (int i = 0; i < allShows.Shows.Length; i++)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((taskId) =>
{
showCast.showCastList.Add(MapResponse(allShows.Shows[i]));
}));
pool.Release();
t.Start(i);
}
}
//for (int i = 0; i < allShows.Shows.Length; i++)
//{
// showCast.showCastList.Add(MapResponse(allShows.Shows[i]));
//}
return showCast.showCastList;
}
public ShowData MapResponse(Show s)
{
CastResponse castres = new CastResponse();
castres.CastlistResponse = (GetShowCast(s.id)).CastlistResponse;
ShowData sd = new ShowData();
sd.id = s.id;
sd.name = s.name;
if (castres.CastlistResponse != null && castres.CastlistResponse.Any())
{
sd.cast = new List<CastData>();
foreach (var item in castres.CastlistResponse)
{
CastData cd = new CastData();
cd.birthday = item.person.birthday;
cd.id = item.person.id;
cd.name = item.person.name;
sd.cast.Add(cd);
}
}
return sd;
}
public ShowResponse GetAllShows()
{
ShowResponse response = new ShowResponse();
string showUrl = ClientAPIUtils.apiUrl + "shows";
response.Shows = JsonConvert.DeserializeObject<Show[]>(ClientAPIUtils.GetDataFromUrl(showUrl));
return response;
}
public CastResponse GetShowCast(int showid)
{
CastResponse res = new CastResponse();
string castUrl = ClientAPIUtils.apiUrl + "shows/" + showid + "/cast";
res.CastlistResponse = JsonConvert.DeserializeObject<List<Cast>>(ClientAPIUtils.GetDataFromUrl(castUrl));
return res;
}
public List getallshowntheircast()
{
ShowResponse allShows=GetAllShows();
ShowCasts showCast=新的ShowCasts();
showCast.showCastList=新列表();
正在使用(信号量池=新信号量(20,20))
{
for(int i=0;i
{
showCast.showCastList.Add(MapResponse(allShows.Shows[i]);
}));
pool.Release();
t、 启动(i);
}
}
//for(int i=0;i
所有的电话都应该打,但我不确定他们在哪里被中止,甚至请让我知道如何检查通话率 我假设您的目标是一次处理所有关于节目的数据,但不超过20个。 对于这种任务,您可能应该使用
ThreadPool
,并使用SetMaxThreads
限制并发线程的最大数量
您必须确保用于存储结果的集合是线程安全的
showCast.showCastList = new List<ShowData>();
我没有测试这个解决方案;可能会出现其他问题
这个程序的另一个问题是它不等待所有线程完成。一旦所有线程启动;节目将结束。有可能(在您的情况下,我确信)不是所有线程都完成了它的操作;这就是为什么程序结束时会产生约240个数据包
thread.Join();
但是如果在Start()
之后立即调用,它将停止主线程,直到它完成为止,因此为了保持程序的并发性,您需要创建一个线程列表,并在程序结束时将它们连接起来。这不是最好的解决办法。如何等待程序可以添加到ThreadPool
最后请注意,您不能像那样访问循环计数器。稍后评估循环计数器的最终值,并运行测试I;代码有两次处理奇数记录和跳过偶数记录的倾向。发生这种情况是因为循环在执行前一个线程之前增加计数器,并导致访问数组边界之外的元素
可能的解决方案是创建将创建线程的方法。在下一个循环通过之前,将其置于单独的方法中,将对allShows.Shows[i]
进行评估,以show
public void CreateAndStartThread(Show show, Semaphore pool, ShowCasts showCast)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((s) => {
showCast.showCastList.Add(MapResponse((Show)s));
pool.Release();
}));
t.Start(show);
}
并发编程是很棘手的,我强烈建议大家做一些关于常见陷阱的练习。关于C#编程的书肯定有一两章是关于这个主题的。有很多关于这个主题的在线课程和教程可供学习
编辑:
工作解决方案。可能还有一些问题
public ShowCasts GetAllShowAndTheirCast()
{
ShowResponse allShows = GetAllShows();
ConcurrentBag<ShowData> result = new ConcurrentBag<ShowData>();
using (var countdownEvent = new CountdownEvent(allShows.Shows.Length))
{
using (Semaphore pool = new Semaphore(20, 20))
{
for (int i = 0; i < allShows.Shows.Length; i++)
{
CreateAndStartThread(allShows.Shows[i], pool, result, countdownEvent);
}
countdownEvent.Wait();
}
}
return new ShowCasts() { showCastList = result.ToList() };
}
public void CreateAndStartThread(Show show, Semaphore pool, ConcurrentBag<ShowData> result, CountdownEvent countdownEvent)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((s) =>
{
result.Add(MapResponse((Show)s));
pool.Release();
countdownEvent.Signal();
}));
t.Start(show);
}
public ShowCasts getallshowtheircast()
{
ShowResponse allShows=GetAllShows();
ConcurrentBag结果=新ConcurrentBag();
使用(var countdownEvent=new countdownEvent(allShows.Shows.Length))
{
正在使用(信号量池=新信号量(20,20))
{
for(int i=0;i
{
结果.添加(MapResponse((Show)s));
pool.Release();
倒计时事件。信号();
}));
t、 开始(表演);
}
Waitone的使用方式没有多大意义。WaitOne用于两个不同的线程。我想你应该用锁来代替。
public ShowCasts GetAllShowAndTheirCast()
{
ShowResponse allShows = GetAllShows();
ConcurrentBag<ShowData> result = new ConcurrentBag<ShowData>();
using (var countdownEvent = new CountdownEvent(allShows.Shows.Length))
{
using (Semaphore pool = new Semaphore(20, 20))
{
for (int i = 0; i < allShows.Shows.Length; i++)
{
CreateAndStartThread(allShows.Shows[i], pool, result, countdownEvent);
}
countdownEvent.Wait();
}
}
return new ShowCasts() { showCastList = result.ToList() };
}
public void CreateAndStartThread(Show show, Semaphore pool, ConcurrentBag<ShowData> result, CountdownEvent countdownEvent)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((s) =>
{
result.Add(MapResponse((Show)s));
pool.Release();
countdownEvent.Signal();
}));
t.Start(show);
}