Насколько неправильным является использование такого кода

#c# #.net #multithreading #c#-2.0

#c# #.net #многопоточность #c #-2.0

Вопрос:

У меня есть код для вызова асинхронных блоков.

     private delegate void MyDelegate();
    void Async(MyDelegate t) {
        Thread thread = new Thread(new ThreadStart(t));
        thread.IsBackground = true;
        thread.Start();
    }
 

И затем:

 Async(delegate() {
    // code
});
 

Я использую его, но я уверен, что это неправильный способ сделать это. В чем проблемы с этим методом?

Комментарии:

1. Предполагая, что вы просто хотите запустить новый поток, который запускает какой-то делегат, это идеальное решение. Почему вы считаете, что это неправильно, и чего вы пытаетесь достичь?

2. Я не уверен, что это неправильно, но это выглядит неубедительно каждый раз, когда я хочу, чтобы что-то не блокировало мой графический интерфейс, чтобы запустить его таким образом. Особенно, если я вызываю его много раз в секунду.

3. @blez: Если вы вызываете это много раз в секунду, вы почти наверняка должны использовать пул потоков.

Ответ №1:

Во-первых, кажется, нет смысла объявлять своего собственного делегата. Почему бы просто не:

 void Async(ThreadStart t) {
    Thread thread = new Thread(t);
    thread.IsBackground = true;
    thread.Start();
}
 

? Лично я не вижу, чтобы я хотел делать это достаточно часто (и без возможности узнать, как продвигается задача), чтобы оправдать отдельный метод. Если вы используете .NET 4, вам следует заглянуть в библиотеку параллельных задач, которая по-прежнему позволяет запускать асинхронные задачи, но более полнофункциональным способом. (РЕДАКТИРОВАТЬ: Хорошо, так что вы не можете использовать это из .NET 2 — это стоит иметь в виду на будущее.)

Вы также можете рассмотреть возможность использования BeginInvoke метода для делегатов, который позволяет вам в любом случае легко запускать их в пуле потоков и передавать аргументы:

 Action<string, int> action = (name, age) => { ... };

IAsyncResult result = action.BeginInvoke("Jon", 35, null);
// Now you can use result if you want...
 

РЕДАКТИРОВАТЬ: Теперь вы сказали, что будете делать это несколько раз в секунду. Предполагая, что это краткосрочная задача, вы почти наверняка должны использовать для этого пул потоков. Как и в приведенном выше примере, вы также можете использовать ThreadPool.QueueUserWorkItem его для добавления задачи в пул потоков. Это будет более эффективно (за счет повторного использования потока), чем создавать новый поток каждый раз, когда у вас есть задача.

Комментарии:

1. Я использую его для тяжелых задач и для многих небольших задач (например, 100 звонков в секунду). Всегда ли использование пула потоков является лучшим вариантом? Я не использовал Action, это третий способ вызова асинхронного кода?

2. @blez: Action<,> это всего лишь примерный тип делегата (на самом деле из .NET 3.5, но это всего лишь тип делегата — очевидно, вы можете объявить свой собственный). У всех делегатов есть BeginInvoke методы. Вы обязательно должны использовать пул потоков для краткосрочных задач. Те, что работают дольше, могли бы разумно использовать отдельные потоки.

Ответ №2:

Поскольку у вас уже есть делегат

 private delegate void MyDelegate();
 

вы можете сделать это

 new MyDelegate(delegate
{
    // code
}).BeginInvoke(null, null);
 

Он будет использовать потоки пула потоков, чтобы вы не перегружали время выполнения слишком большим количеством потоков.