int[] ids = new[] { 1, 2, 3, 4, 5 }; Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
Несмотря на то, что вы выполняете операции параллельно с указанным выше кодом, этот код блокирует каждый поток, в котором выполняется каждая операция. Например, если сетевой вызов занимает 2 секунды, каждый поток висит в течение 2 секунд без каких-либо действий, кроме ожидания.
int[] ids = new[] { 1, 2, 3, 4, 5 }; Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
С другой стороны, приведенный выше код с
WaitAll
также блокирует нити и ваши потоки не будут свободны обрабатывать любую другую работу до окончания операции.Рекомендуемый подход
Я предпочел бы
WhenAll
, который будет выполнять ваши операции асинхронно в Parallel.public async Task DoWork() { int[] ids = new[] { 1, 2, 3, 4, 5 }; await Task.WhenAll(ids.Select(i => DoSomething(1, i, blogClient))); }
Фактически, в приведенном выше case, вам даже не нужно
await
, вы можете просто прямо вернуться из метода, поскольку у вас нет никаких продолжений:blockquote>public Task DoWork() { int[] ids = new[] { 1, 2, 3, 4, 5 }; return Task.WhenAll(ids.Select(i => DoSomething(1, i, blogClient))); }
Чтобы поддержать это, здесь представляет собой подробное сообщение в блоге, в котором рассматриваются все альтернативы и их преимущества / недостатки: Как и где параллельный асинхронный ввод-вывод с веб-интерфейсом ASP.NET
К сожалению, очень трудно убедить компилятор об определенных реализациях T. Один (противный) подход должен бросить для возражения в середине (обратите внимание, что это упакует и распакует типы значения):
int i = (int)(object)this.value;
i++;
this.value = (T)(object)i;
Ужасный, но это работает. В.NET 3.5 у меня есть некоторые лучшие обертки для универсальной арифметики, здесь . Класс Оператора является частью MiscUtil; на самом простом уровне я подозреваю, что AddAlternative работал бы очень хорошо:
this.value = Operator.AddAlternative(this.value, 1);
Это должно вывести неявный < T, int> автоматически, или можно добавить их сами:
this.value = Operator.AddAlternative<T,int>(this.value, 1);
Преимущество : Это предпочтительно для исходного кода, поскольку он на самом деле не заботится об оригинале T - он будет работать на любой тип (даже Ваше собственное), который поддерживает "T + (T, интервал)".
я думаю, что существует также ChangeType, скрывающийся вокруг где-нибудь там...
[редактирование] Collin K и другие делают допустимое замечание об архитектурных последствиях - но быть прагматичным существуют времена, когда T действительно имеет значение так очень..., но я согласился бы с предотвращением этого типа специализации если действительно необходимый. Это сказало (согласно моему комментарию к сообщению Collin), способность выполнить вещи как основная арифметика (инкремент, подразделение Int32, и т.д.) на (например), Matrix< T> [для T в десятичном/плавающем/международном/двойном/и т.д.] часто очень ценно.
По-моему, определенный для типа код в универсальном классе является запахом кода. Я осуществил бы рефакторинг его для получения чего-то вроде этого:
public class MyClass<T>
{
...
}
public class IntClass : MyClass<int>
{
public void IncrementMe()
{
this.value++;
}
}
Статический контроль типов C# не позволит Вам сделать так, но можно одурачить его с кастингом для возражения. Я не рекомендовал бы делать это, это, вероятно, показывает архитектурную проблему, но так или иначе:
using System;
class Foo<T>
{
public T value;
public void Increment()
{
if (value is int) value = (T)(object)(((int)(object)value)+1);
}
}
static class Program
{
static void Main()
{
Foo<int> x = new Foo<int>();
x.Increment();
x.Increment();
Console.WriteLine(x.value);
}
}
Я не думаю, что понимаю то, что Вы после. Если Вы требуете, чтобы что-то было определенным типом, то Вы, вероятно, не должны использовать Дженерики. Вы могли, это просто кажется глупым. Это сделает то, что Вы спрашиваете, но я не рекомендую его.
namespace GenericsOne
{
using System;
class Program
{
static void Main(string[] args)
{
Sample<int> one = new Sample<int>();
one.AddFive(10);
// yes, this will fail, it is to show why the approach is generally not a good one.
Sample<DateTime> two = new Sample<DateTime>();
two.AddFive(new DateTime());
}
}
}
namespace GenericsOne
{
using System;
public class Sample<T>
{
public int AddFive(T number)
{
int junk = 0;
try
{
junk = Convert.ToInt32(number);
}
catch (Exception)
{
Console.WriteLine("Nope");
}
return junk + 5;
}
}
}
Поэтому я действительно хочу числовой или операционные ограничения в C#4.
ответ @Marc Gravell является лучшим способом вокруг этого (+1), но это - frustating, как это - проблема для дженериков.