Как правильно организовать многопоточность на C#?
Если вам не жалко, можете поделиться исходником, где есть многопоточнось. Смотрел видео видео одного чекера работает в 200-300 потоков спокойно, скорость результата хорошая. Сам тоже написал чекер, если около ста строк, то в 10 потоков работает хорошо, но если же строк около 1к, выводит результат с первых 100-150 строк, дальше данные в лог не записываются, при этом программа продолжает чекать, ресурсы пк потребляет, хоть и мало, и интернет тратит.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Leaf.xNet;
using System.Threading;
using System.Text.RegularExpressions;
namespace mail_cheсk
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
List<string> listSource = new List<string>();
List<Thread> ListThread = new List<Thread>();
public static int iPrx = 0;
bool lifeThread = false;
//*** Дизайн ***//
#region
[DllImport("user32", CharSet = CharSet.Auto)]
internal extern static bool PostMessage(IntPtr hWnd, uint Msg, uint WParam, uint LParam);
[DllImport("user32", CharSet = CharSet.Auto)]
internal extern static bool ReleaseCapture();
const uint WM_SYSCOMMAND = 0x0112;
const uint DOMOVE = 0xF012;
const uint DOSIZE = 0xF008;
private void label2_MouseMove(object sender, MouseEventArgs e)
{
label2.ForeColor = Color.Red;
}
private void label2_MouseLeave(object sender, EventArgs e)
{
label2.ForeColor = Color.FromArgb(221, 79, 66);
}
private void label2_Click(object sender, EventArgs e)
{
Close();
}
private void label3_MouseMove(object sender, MouseEventArgs e)
{
label3.ForeColor = Color.FromArgb(1, 1, 248);
}
private void label3_MouseLeave(object sender, EventArgs e)
{
label3.ForeColor = Color.White;
}
private void label3_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
private void panel3_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
PostMessage(this.Handle, WM_SYSCOMMAND, DOMOVE, 0);
}
private void panel4_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
PostMessage(this.Handle, WM_SYSCOMMAND, DOMOVE, 0);
}
private void label1_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
PostMessage(this.Handle, WM_SYSCOMMAND, DOMOVE, 0);
}
private void label10_MouseDown(object sender, MouseEventArgs e)
{
ReleaseCapture();
PostMessage(this.Handle, WM_SYSCOMMAND, DOMOVE, 0);
}
private void button5_Click(object sender, EventArgs e)
{
if (panel5.Visible == false)
{
panel7.Visible = false;
panel5.Visible = true;
}
else
{
panel5.Visible = false;
}
}
private void button6_Click(object sender, EventArgs e)
{
if (panel7.Visible == false)
{
panel5.Visible = false; ;
panel7.Visible = true;
}
else
{
panel7.Visible = false;
}
}
#endregion
///*** Работа с файлами ///
#region
void Load_proxy()
{
using (var open = new OpenFileDialog())
{
open.Filter = "Proxy (*.txt)|*.txt";
if (open.ShowDialog() == DialogResult.OK)
{
Data.Proxy_user.Clear();
label5.Text = "Добавлено прокси " + File.ReadLines(open.FileName).Count();
Data.Proxy_user.AddRange(File.ReadLines(open.FileName));
GC.Collect();
}
}
}
private void btn_Save_Good_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
File.WriteAllLines(saveFileDialog.FileName, Data.Save_good.ToArray());
}
}
private void btn_Save_Bad_Click(object sender, EventArgs e)
{
}
private void btn_Save_Error_Click(object sender, EventArgs e)
{
}
#endregion
private void Form1_Load(object sender, EventArgs e)
{
btStop.Enabled = false;
}
private void btSource_Click(object sender, EventArgs e)
{
try
{
var FileDialog = new OpenFileDialog(); FileDialog.Filter = "Source List (*.txt)|*.txt";
if (FileDialog.ShowDialog() == DialogResult.OK)
{
listSource.Clear();
foreach (var value in File.ReadAllLines(FileDialog.FileName).Distinct())
{
if (!string.IsNullOrEmpty(value))
{
listSource.Add(value);
}
}
label6.Text = "Добавлено почт " + listSource.Count.ToString();
}
}
catch
{
MessageBox.Show("Add Source File", "Error");
}
}
private void work()
{
while (listSource.Count > 0 && lifeThread)
{
string email_user = null;
if (listSource.Count > 0)
{
email_user = listSource[0];
listSource.RemoveAt(0);
}
Check(email_user);
}
}
private string Token()
{
try
{
string token = null;
var request = new HttpRequest();
request.UserAgent = Http.ChromeUserAgent();
HttpResponse response = request.Get("https://www.instagram.com/");
token = Regex.Match(response.ToString(), "csrf_token\":\"(.*?)\"").Groups[1].Value;
return token;
}
catch { } return null;
}
private void Check(string email_user)
{
try
{
string response = "";
using (HttpRequest request = new HttpRequest())
{
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("X-Requested-With", "XMLHttpRequest");
request.AddHeader("X-CSRFToken", Token());
request.AddHeader("Origin", "https://www.instagram.com");
request.AddHeader("Referer", "https://www.instagram.com/");
request.KeepAlive = true;
request.UserAgent = Http.RandomUserAgent();
RequestParams param = new RequestParams();
param["email"] = email_user;
response = request.Post("https://www.instagram.com/accounts/web_create_ajax/attempt/?hl=ru", param).ToString();
if (response.Contains(email_user))
{
lock (this)
{
string[] names = email_user.Split('@');
string name = names[0];
Invoke((MethodInvoker)delegate
{
richTextBox1.AppendText(Environment.NewLine + name + " Не валидный. Поток № " + Thread.CurrentThread.ManagedThreadId);
label8.Text = Convert.ToString(Convert.ToInt32(label8.Text) + 1);
});
}
}
if (response.Contains("This field is required"))
{
lock (this)
{
string[] names = email_user.Split('@');
string name = names[0];
Invoke((MethodInvoker)delegate
{
richTextBox1.AppendText(Environment.NewLine + name + " Валидный. Поток № " + Thread.CurrentThread.ManagedThreadId);
label7.Text = Convert.ToString(Convert.ToInt64(label7.Text) + 1);
});
}
}
}
}
catch { }
}
private void workStart()
{
lifeThread = true;
ListThread.Clear();
for (int i = 0; i < Convert.ToInt32(numericUpDown2.Value); i++)
{
Thread td = new Thread(work);
ListThread.Add(td);
td.Start();
}
btn_Start.Enabled = false;
btStop.Enabled = true;
}
private void btn_Start_Click(object sender, EventArgs e)
{
if (listSource.Count > 0)
{
Thread.Sleep(150);
workStart();
}
else { MessageBox.Show("База email пуста, добавьте почты!"); }
}
private void workStop()
{
lifeThread = false;
foreach (Thread thread in ListThread)
{
thread.Abort();
}
btStop.Enabled = false;
btn_Start.Enabled = true;
MessageBox.Show("Работа остановлена");
}
private void btStop_Click(object sender, EventArgs e)
{
workStop();
}
}
}
Ответы (1 шт):
Изучайте Task и async/await, иначе большинство ваших потоков будут висеть впустую, тратя на пустые циклы ожидания ввода-вывода ядра/потоки процессора, число которых достаточно мало.
А главное - обычные коллекции не потокобезопасны. Используйте вместо List что-нибудь из System.Collections.Concurrent, например ConcurrentQueue. Ну, либо заворачивайте в функции work работу со списком в lock, если хотите по-старинке всё делать. У вас честно говоря в целом очень не оптимальный код, на async/await всё можно написать гораздо проще и понятнее.