Нубский вопрос про многопоток

ffeniks

Client
Регистрация
03.06.2016
Сообщения
312
Благодарностей
410
Баллы
63
Здравствуйте, подскажите как реализовать.
В екселе 1000 строк (каждая строка это индивидуальное задание), которое необходимо выполнять в цикле с определённым промежутком времени.
Ставлю 20 потоков, каждый поток бегает - проверяет строки и выполняет задание.
Теперь вопрос,
как мне задать в переменных что эта строка занята и её проверять нельзя, с условием того что одновременно на неё могут перейти сразу несколько потоков и при этом, если постер вырубить грубо (либо инет отвалится), остальные потоки должны быть в курсе что данный поток освободился.

(т.е. идея - в конце шаба ставить что поток свободен не совсем подходит. т.к. если постер вырубить этот поток(строка) будет вечно открыт, хотя и не работать. )

кто и как реализует такие моменты в шабах? (думал может в сторону глобальных переменных подумать, но не совсем умею с ними работать, да и логику до конца так и не могу продумать, т.к. если постер вырубить поток останется не закрытым)

help? =)
 

ZennoScript

Moderator
Регистрация
04.03.2011
Сообщения
4 450
Благодарностей
1 885
Баллы
113
Как метку можно ставить время взятия. При следующих запросах проверять - если прошел час, значит метка не рабочая.
 

VladZen

Administrator
Команда форума
Регистрация
05.11.2014
Сообщения
22 453
Благодарностей
5 912
Баллы
113
Может проще брать строку из таблицы с удалением, но не сохранять изменения таблицы в файл?
 

ZennoScript

Moderator
Регистрация
04.03.2011
Сообщения
4 450
Благодарностей
1 885
Баллы
113
Может прозе брать строку из таблицы с удалением, но не сохранять изменения таблицы в файл?
А что это даст? В таком случае следующий поток так же может взять эту строку.
 

S16er1um

Client
Регистрация
14.04.2016
Сообщения
826
Благодарностей
240
Баллы
43
Если бы так делал я - я бы сделал в таблице столбец для меток. Типа когда поток берёт строку - он записывает например в столбец 1 вместо нуля (по умолчанию). в конце работы поток записывает в столбец 0.
каждый следующий поток - когда берёт строку проверяет значение этой страки в данном столбце. если там стоит 1 - значит строка в работе и нужно взять другую. если в строке 0 - то всё ок и можно работать дальше.

а в случае bad end можно чтоб в эту строку записывалась например не 0 и 1, а 2ка (как исключение). а дальше уже сами решайте что делать с этой логикой
то есть пошагово.
1. Взятие строки (без удаления).
2. Проверка столбца (столбец всегда статичен для всех строк. поэтому ячейку вы будете всегда знать которую берёте. Строка {Var.Stroka} , столбец допустим 0. для меток)
3. Если в ячейке 0 - записываем 1 и работаем. Если в ячейке 1 - ничего не делаем и берём другую строку.
4. В конце задания - записываем в ячейку 0.
В случае какой либо ошибки - записываем 2 (или на ваше усмотрение)
 

VladZen

Administrator
Команда форума
Регистрация
05.11.2014
Сообщения
22 453
Благодарностей
5 912
Баллы
113
А что это даст? В таком случае следующий поток так же может взять эту строку.
Тогда можно брать строку с удалением и записывать её в конец таблицы по завершении задания.
 

ZennoScript

Moderator
Регистрация
04.03.2011
Сообщения
4 450
Благодарностей
1 885
Баллы
113
Если бы так делал я - я бы сделал в таблице столбец для меток. Типа когда поток берёт строку - он записывает например в столбец 1 вместо нуля (по умолчанию). в конце работы поток записывает в столбец 0.
каждый следующий поток - когда берёт строку проверяет значение этой страки в данном столбце. если там стоит 1 - значит строка в работе и нужно взять другую. если в строке 0 - то всё ок и можно работать дальше.

а в случае bad end можно чтоб в эту строку записывалась например не 0 и 1, а 2ка (как исключение). а дальше уже сами решайте что делать с этой логикой
то есть пошагово.
1. Взятие строки (без удаления).
2. Проверка столбца (столбец всегда статичен для всех строк. поэтому ячейку вы будете всегда знать которую берёте. Строка {Var.Stroka} , столбец допустим 0. для меток)
3. Если в ячейке 0 - записываем 1 и работаем. Если в ячейке 1 - ничего не делаем и берём другую строку.
4. В конце задания - записываем в ячейку 0.
В случае какой либо ошибки - записываем 2 (или на ваше усмотрение)

Этот вариант не подойдёт в случаях, если зенка падает или жестко прерывается задача. В этих случаях ничего никуда не допишется. Строка останется отмеченной, как "В работе".
 

ffeniks

Client
Регистрация
03.06.2016
Сообщения
312
Благодарностей
410
Баллы
63
Если бы так делал я - я бы сделал в таблице столбец для меток. Типа когда поток берёт строку - он записывает например в столбец 1 вместо нуля (по умолчанию). в конце работы поток записывает в столбец 0.
каждый следующий поток - когда берёт строку проверяет значение этой страки в данном столбце. если там стоит 1 - значит строка в работе и нужно взять другую. если в строке 0 - то всё ок и можно работать дальше.

а в случае bad end можно чтоб в эту строку записывалась например не 0 и 1, а 2ка (как исключение). а дальше уже сами решайте что делать с этой логикой
то есть пошагово.
1. Взятие строки (без удаления).
2. Проверка столбца (столбец всегда статичен для всех строк. поэтому ячейку вы будете всегда знать которую берёте. Строка {Var.Stroka} , столбец допустим 0. для меток)
3. Если в ячейке 0 - записываем 1 и работаем. Если в ячейке 1 - ничего не делаем и берём другую строку.
4. В конце задания - записываем в ячейку 0.
В случае какой либо ошибки - записываем 2 (или на ваше усмотрение)
Так не подойдёт если 1 из зенок отвалится, а другие будут работать (то эти строки так и останутся с метками) 1, т.е. по факту они не будут работать и потоки их брать так же не будут
 

ffeniks

Client
Регистрация
03.06.2016
Сообщения
312
Благодарностей
410
Баллы
63
Как метку можно ставить время взятия. При следующих запросах проверять - если прошел час, значит метка не рабочая.
Это пока что действительно более - менее верный вариант по логике, но для некоторых проектов он не подойдёт, если время ожидания не фиксированное. И так же - есть вероятность что сразу два потока (сделают сравнение и увидят что время ожидания вышло) - оба одновременно возьмут строку - а это нежелательный - элемент в системе.

Спасибо за эту подсказку.
 

ZennoScript

Moderator
Регистрация
04.03.2011
Сообщения
4 450
Благодарностей
1 885
Баллы
113
Это пока что действительно более - менее верный вариант по логике, но для некоторых проектов он не подойдёт, если время ожидания не фиксированное. И так же - есть вероятность что сразу два потока (сделают сравнение и увидят что время ожидания вышло) - оба одновременно возьмут строку - а это нежелательный - элемент в системе.

Спасибо за эту подсказку.
1. Время для каждого варианта можно ставить своё.
2. Лочте таблицу при работе с ней. Тогда не получится, что 2 потока возьмут одну строку.
 

ffeniks

Client
Регистрация
03.06.2016
Сообщения
312
Благодарностей
410
Баллы
63

serg1208

Client
Регистрация
17.04.2018
Сообщения
331
Благодарностей
15
Баллы
18
1. Время для каждого варианта можно ставить своё.
2. Лочте таблицу при работе с ней. Тогда не получится, что 2 потока возьмут одну строку.
Но почему в моем случае несколько потоков успевают взять одну строку ?

//var isDebug = Global.Variables.IsDebugMode;
Boolean isDebug = false;
try
{
instance.ClearCookie();
instance.ClearCache();
project.Variables["userAgent"].Value = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36";
var accounts = project.Tables["accounts"];

lock(SyncObjects.TableSyncer)
{
var asins = project.Tables["asins"];
if(accounts.RowCount == 0)
{
project.SendWarningToLog("Список accounts пустой", true);
return null;
}

if(asins.RowCount == 0)
{
project.SendWarningToLog("Список asins пустой", true);
return null;
}

//---

var row = accounts.GetRow(0).ToList();
//if(!isDebug) accounts.DeleteRow(0);
string parent_path = System.IO.Directory.GetParent(project.Directory).ToString();
//project.SendInfoToLog(parent_path, true);
project.Variables["ebayLogin"].Value = row[0];
project.Variables["ebayPass"].Value = row[1];
project.Variables["proxy"].Value = row.Count > 2 ? row[2] : "";

//---
string bad_asins = File.ReadAllText(parent_path + "\\badASINs.txt");
string work_asins = File.ReadAllText(project.Directory + "\\EbayLister\\workASINs.txt");
//string stop_words = File.ReadAllText(parent_path + "\\stopWords.txt");
var stop_words = project.Lists["stop_words"];
int index = 0;
string stop_word = "";
string stop_title = "";
while (true) {
int value = ++index;
row = asins.GetRow(0).ToList();
if(!isDebug) asins.DeleteRow(0);
if (!bad_asins.Contains(row[0]) && !work_asins.Contains(row[0])) {
string title = row.Count > 1 ? row[1] : "";
if (title == "") {
project.Variables["asin"].Value = row[0];
project.Variables["title"].Value = "";
break;
} else {
string low_title = title.ToLower();
Boolean isFind = false;
string word = "";
string [] words = null;
string str = "";
for (int i = 0; i < stop_words.Count; i++) {
word = stop_words;
words = word.Split(' ');
if (words.Length > 1) {
if (low_title.Contains(word)) {
stop_word = word;
stop_title = title;
isFind = true;
break;
}
} else {
str = "\\b" + word + "\\b";
if (Regex.IsMatch(title, @str, RegexOptions.IgnoreCase)) {
stop_word = word;
stop_title = title;
isFind = true;
break;
}
}
}
if (!isFind) {
project.Variables["asin"].Value = row[0];
project.Variables["goodsSellPrice"].Value = row[1];
break;
} else {
project.SendInfoToLog(row[0] + " - удаляем, т. к. Title - " + stop_title + " имеет запрещенное слово " + stop_word, true);
lock(SyncObjects.TableSyncer) {
var row1 = new List<string>() {
row[0], stop_title
};
project.Tables["asinsBad"].AddRow(row1);
}
}
}

} else {
project.SendInfoToLog(row[0] + " - удаляем, т. к. этот ASIN в черном списке или в рабочем списке" , true);
}
if (value > 10) {
throw new Exception("Бесконечный цикл");
}
}
project.SendInfoToLog(project.Variables["asin"].Value + " - " + project.Variables["goodsSellPrice"].Value, true);
}
var path = project.Directory + "\\EbayLister\\Profiles\\" + project.Variables["ebayLogin"].Value.Split('@')[0] + ".zpprofile";
if(File.Exists(path))
{
project.Profile.Load(path);
}
//instance.SetProxy(project.Variables["proxy"].Value);
}
catch(Exception e)
{
project.SendErrorToLog(e.ToString(), true);
return null;
}
 

serg1208

Client
Регистрация
17.04.2018
Сообщения
331
Благодарностей
15
Баллы
18
Но почему в моем случае несколько потоков успевают взять одну строку ?

//var isDebug = Global.Variables.IsDebugMode;
Boolean isDebug = false;
try
{
instance.ClearCookie();
instance.ClearCache();
project.Variables["userAgent"].Value = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36";
var accounts = project.Tables["accounts"];

lock(SyncObjects.TableSyncer)
{
var asins = project.Tables["asins"];
if(accounts.RowCount == 0)
{
project.SendWarningToLog("Список accounts пустой", true);
return null;
}

if(asins.RowCount == 0)
{
project.SendWarningToLog("Список asins пустой", true);
return null;
}

//---

var row = accounts.GetRow(0).ToList();
//if(!isDebug) accounts.DeleteRow(0);
string parent_path = System.IO.Directory.GetParent(project.Directory).ToString();
//project.SendInfoToLog(parent_path, true);
project.Variables["ebayLogin"].Value = row[0];
project.Variables["ebayPass"].Value = row[1];
project.Variables["proxy"].Value = row.Count > 2 ? row[2] : "";

//---
string bad_asins = File.ReadAllText(parent_path + "\\badASINs.txt");
string work_asins = File.ReadAllText(project.Directory + "\\EbayLister\\workASINs.txt");
//string stop_words = File.ReadAllText(parent_path + "\\stopWords.txt");
var stop_words = project.Lists["stop_words"];
int index = 0;
string stop_word = "";
string stop_title = "";
while (true) {
int value = ++index;
row = asins.GetRow(0).ToList();
if(!isDebug) asins.DeleteRow(0);
if (!bad_asins.Contains(row[0]) && !work_asins.Contains(row[0])) {
string title = row.Count > 1 ? row[1] : "";
if (title == "") {
project.Variables["asin"].Value = row[0];
project.Variables["title"].Value = "";
break;
} else {
string low_title = title.ToLower();
Boolean isFind = false;
string word = "";
string [] words = null;
string str = "";
for (int i = 0; i < stop_words.Count; i++) {
word = stop_words;
words = word.Split(' ');
if (words.Length > 1) {
if (low_title.Contains(word)) {
stop_word = word;
stop_title = title;
isFind = true;
break;
}
} else {
str = "\\b" + word + "\\b";
if (Regex.IsMatch(title, @str, RegexOptions.IgnoreCase)) {
stop_word = word;
stop_title = title;
isFind = true;
break;
}
}
}
if (!isFind) {
project.Variables["asin"].Value = row[0];
project.Variables["goodsSellPrice"].Value = row[1];
break;
} else {
project.SendInfoToLog(row[0] + " - удаляем, т. к. Title - " + stop_title + " имеет запрещенное слово " + stop_word, true);
lock(SyncObjects.TableSyncer) {
var row1 = new List<string>() {
row[0], stop_title
};
project.Tables["asinsBad"].AddRow(row1);
}
}
}

} else {
project.SendInfoToLog(row[0] + " - удаляем, т. к. этот ASIN в черном списке или в рабочем списке" , true);
}
if (value > 10) {
throw new Exception("Бесконечный цикл");
}
}
project.SendInfoToLog(project.Variables["asin"].Value + " - " + project.Variables["goodsSellPrice"].Value, true);
}
var path = project.Directory + "\\EbayLister\\Profiles\\" + project.Variables["ebayLogin"].Value.Split('@')[0] + ".zpprofile";
if(File.Exists(path))
{
project.Profile.Load(path);
}
//instance.SetProxy(project.Variables["proxy"].Value);
}
catch(Exception e)
{
project.SendErrorToLog(e.ToString(), true);
return null;
}
 

Кто просматривает тему: (Всего: 4, Пользователи: 0, Гости: 4)