Многопоточная работа со списком

martens

Client
Регистрация
27.07.2015
Сообщения
97
Благодарностей
3
Баллы
8
Прочитал тут

http://zennolab.com/wiki/ru:project_maker:проекты:редактирование_проекта:таблицы

, что можно работать со списком многопоточно, только если в одно действие

Мне нужно выполнять следующие операции со списком

1)Узнать, есть ли уже в списке значение определённой переменной
2) если его нет - сразу добавлять его в конец списка

Как то можно сделать это в одно действие? чтоб если несколько потоков начнут это выполнять, одно и то же значение не могло 2 раза добавиться в таблицу
 

VladZen

Administrator
Команда форума
Регистрация
05.11.2014
Сообщения
22 453
Благодарностей
5 913
Баллы
113
Прочитал тут

http://zennolab.com/wiki/ru:project_maker:проекты:редактирование_проекта:таблицы

, что можно работать со списком многопоточно, только если в одно действие

Мне нужно выполнять следующие операции со списком

1)Узнать, есть ли уже в списке значение определённой переменной
2) если его нет - сразу добавлять его в конец списка

Как то можно сделать это в одно действие? чтоб если несколько потоков начнут это выполнять, одно и то же значение не могло 2 раза добавиться в таблицу
В одно действие это не сделать. Делайте в два, все нормально будет в многопотоке.
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Для этого существует оператор lock (внутри ссылочный объект) { }, а также потокобезопасные коллекции (Concurrent Collections).
 
  • Спасибо
Реакции: martens

martens

Client
Регистрация
27.07.2015
Сообщения
97
Благодарностей
3
Баллы
8
Для этого существует оператор lock (внутри ссылочный объект) { }, а также потокобезопасные коллекции (Concurrent Collections).
То есть для данной задачи одного оператора lock хватит? или нужно Concurrent Collections ещё дополнительно использовать?

var bot = project.Lists["usa"];
var stron = "7564535";
var str = "";
int yyy = 0;
lock(SyncObjects.ListSyncer)
{
for (int i=0; i<22000000; i++)
{
str = bot;
if (str == stron)
yyy = 1;
}
}
return yyy;

Так должно быть?
"SyncObjects.ListSyncer" указывать в скобках после lock или что то другое?
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
lock должно хватить, но я вообще хз как разрабы реализовали эти кубики и считаются ли они в разных потоках одним и тем же участком кода или нет и нигде это не описано
SyncObjects.ListSyncer" ты правильно указал, так как он ссылочный тип
 
  • Спасибо
Реакции: martens

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
824
Баллы
93
lock должно хватить, , но я вообще хз как разрабы реализовали эти кубики и считаются ли они в разных потоках одним и тем же участком кода или нет и нигде это не описано
Как то ты неуверенно это говоришь.:D Как тогда многопоточные шабы делаешь?

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

Но даже не это главное. Шаблоны вообще могут быть разные, но синхронизированные между собой.
Вся фишка в двух объектах - SyncObjects.ListSyncer и SyncObjects.TableSyncer
Это два статических объекта(простые object) и т.к. они используются в пределах одной программы, то используя их в конструкции lock, можно синхронизировать выполнение потоков.

SyncObjects.ListSyncer" ты правильно указал, так как он ссылочный тип
Это тут вообще не причем. SyncObjects.ListSyncer это св-во через которое можно получить доступ к объекту.

То есть для данной задачи одного оператора lock хватит? или нужно Concurrent Collections ещё дополнительно использовать?

var bot = project.Lists["usa"];
var stron = "7564535";
var str = "";
int yyy = 0;
lock(SyncObjects.ListSyncer)
{
for (int i=0; i<22000000; i++)
{
str = bot;
if (str == stron)
yyy = 1;
}
}
return yyy;

Так должно быть?
"SyncObjects.ListSyncer" указывать в скобках после lock или что то другое?
Concurrent Collections тут некуда впихивать у зенки свои внутренние классы для работы со списком и таблицей.
Главное, что надо запомнить, это любые изменения вносимые в коллекцию - добавление/удаление надо делать через блокировку(lock), если планируется использовать шаб в много потоке.
Если список просто читается(как в примере), то смысла в блокировке нет.

А ну и в коде есть логическая ошибка, должно быть так
C#:
str = bot[i];
В цикле идет доступ к коллекции project.Lists["usa"] через переменную bot.
 
  • Спасибо
Реакции: impul5e

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Как то ты неуверенно это говоришь.:D Как тогда многопоточные шабы делаешь?

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

Но даже не это главное. Шаблоны вообще могут быть разные, но синхронизированные между собой.
Вся фишка в двух объектах - SyncObjects.ListSyncer и SyncObjects.TableSyncer
Это два статических объекта(простые object) и т.к. они используются в пределах одной программы, то используя их в конструкции lock, можно синхронизировать выполнение потоков.
Я вообще не реализовываю взаимодействие разных потоков шаблонов в зенке, так как не люблю такую неопределенность. Если посмотреть на код в студии, то ты там видишь сразу, что создал кучу объектов класса, запустил для них Thread или Task и ты уже видишь, что они используют одни и те же участки кода и можно легко их залочить.
А в lock можно засунуть любой ссылочный объект, главное, чтобы он использовался в 1 участке кода для блокировки, так как его использование в другом участке заблокирует и этот участок кода. В таком случае желательно обернуть в lock саму таблица/список, с которым ведется работа и потом далее в коде проводить действия с той же таблицей/списком
P.S. ну ты это сам понимаешь насчет lock, я просто для других описал как лучше работать с блокировкой
Это тут вообще не причем. SyncObjects.ListSyncer это св-во через которое можно получить доступ к объекту.
Ну я бы не сказал так, object - ссылка на объект, а сам объект расположен в куче. Мы же можем привести любой тип к типу object. Но тут не все так просто. Все значимые типы наследуются от типа ValueType, а он в свою очередь от типа object, аналогично и с ссылочными значениями, так что нельзя однозначно сказать, что object- ссылочный объект. Но при приведении к типу object, он содержит ссылку на объект и сам объект в куче.
Просто тут вся соль в пуле интернирования строк и объект не должен ссылаться на одно и то же место в памяти.
 
Последнее редактирование:

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
824
Баллы
93
Я вообще не реализовываю взаимодействие разных потоков шаблонов в зенке, так как не люблю такую неопределенность.
Ну а один и тот же то шаб ты запускаешь во много поток? Или у тебя все шабы в один поток работают?:-)

А в lock можно засунуть любой ссылочный объект, главное, чтобы он использовался в 1 участке кода для блокировки, так как его использование в другом участке заблокирует и этот участок кода.
Если ты через блокировку делаешь доступ к какому то ресурсу(список или таблица) и в разных местах, то надо использовать один и тот же объект для блокировки.
Например в одном экшене читается список, берется первая строка удаляется, в другом экшене в этот же список добавляется строка.
И оба эти куска должны выполнятся в lock с одним и тем же объектом, иначе толку не будет от твоей блокировки.
Почему? Да потому что смысл в том, что не зависимо от места где выполняется код, доступ к ресурсу потоки должны получать по очереди.

В таком случае желательно обернуть в lock саму таблица/список, с которым ведется работа и потом далее в коде проводить действия с той же таблицей/списком
Ну дак про таблица/список и шла речь, или я написал что в lock надо чето другое оборачивать.

P.S. ну ты это сам понимаешь насчет lock, я просто для других описал как лучше работать с блокировкой
Ну я бы не сказал так, object - ссылка на объект, а сам объект расположен в куче. Мы же можем привести любой тип к типу object. Но тут не все так просто. Все значимые типы наследуются от типа ValueType, а он в свою очередь от типа object, аналогично и с ссылочными значениями, так что нельзя однозначно сказать, что object- ссылочный объект. Но при приведении к типу object, он содержит ссылку на объект и сам объект в куче.
Просто тут вся соль в пуле интернирования строк и объект не должен ссылаться на одно и то же место в памяти.
Я то понимаю как lock работает.:-)
Про значимые и ссылочные типы знаю, и как что хранится в памяти тоже знаю.
Но другим ты подобными "подробностями" засираешь мозг кучей ненужной инфы, которая нахер не нужна.
И они начинают думать что использовать конструкцию lock очень сложно.
Хотя там надо знать только это.
Главное, что надо запомнить, это любые изменения вносимые в коллекцию - добавление/удаление надо делать через блокировку(lock), если планируется использовать шаб в много потоке.
Если список просто читается(как в примере), то смысла в блокировке нет.
И использовать встроенные в зенку готовые объекты для блокировки. Этого достаточно в 99%.

Большего знать не надо. Кому интересно как это работает на более низком уровне, сам раскопает и узнает.
 
  • Спасибо
Реакции: impul5e

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Ну а один и тот же то шаб ты запускаешь во много поток? Или у тебя все шабы в один поток работают?:-)
Я щас вообще практически не работаю с зенкой, учу c# не покладая рук, особенно занимаюсь SQL синтаксисом, начинаю понимать как работать с БД, Entity Framework и много другого, что по сравнению с зенкой сложнее в разы.
Я делал в ПМ 20 потоков (для каждого потока 1 вкладка, но там пришлось выбросить методы ZennoPoster.HttpGet и ZennoPoster.HttpPost, так как они ложили прогу и глючили). Забросил эту тему из-за того, что для 1 инстанса можно использовать только 1 прокси одновременно, а множество инстансов создавать не пробовал.
Если ты через блокировку делаешь доступ к какому то ресурсу(список или таблица) и в разных местах, то надо использовать один и тот же объект для блокировки.
Я так и делал бы, если была необходимость, но пока такой необходимости не было. Тут итак понятно, что если доступ идет в одной таблице/списку, то один и тот же объект блокировки использовать можно в разных участках кода, но если в этих участках кода нету работы с одним и тем же объектом, то это только замедлит работу. Насчет этой темы можно говорить часами и о том, что эта конструкция работает на уровне ядра ОС, что для переменных есть другие конструкции наподобие interlocked и т.д., ну это опять же мало кому интересно, а кому надо, тот сам найдет или отдельно спросит на форуме.
 
Последнее редактирование:

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
824
Баллы
93
Я щас вообще практически не работаю с зенкой, учу c# не покладая рук, особенно занимаюсь SQL синтаксисом, начинаю понимать как работать с БД, Entity Framework и много другого, что по сравнению с зенкой сложнее в разы.
Ну я рад за тебя, особенно если начал ковырять БД и язык запросов - sql. Но имхо, ты копаешь не в ту сторону, Entity может и нужен будет, но только узко специализированно.
Карочь, ты зря тратитшь время.))
Серьезно, оно нах не нужно особо.)) Я это понял только тогда, когда поковырялся с этой хней.))

А по поводу многопотока. Ты шабы продаешь, они у тебя в многопотоке то работают? А то ты так аккуратно уходишь от вопросов многопоточности в шабах зенки, что возникают вопросы.
Возьму щас у тебя шаб куплю, запущу в +100500 потоков, и все пи...й накроется.:D
Не будет такого?
 

one

Client
Регистрация
22.09.2015
Сообщения
6 833
Благодарностей
1 275
Баллы
113
Например в одном экшене читается список, берется первая строка удаляется, в другом экшене в этот же список добавляется строка.
И оба эти куска должны выполнятся в lock с одним и тем же объектом, иначе толку не будет от твоей блокировки.
А как эта блокировка выполняется? Только сниппетами я так понимаю.
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
А по поводу многопотока. Ты шабы продаешь, они у тебя в многопотоке то работают? А то ты так аккуратно уходишь от вопросов многопоточности в шабах зенки, что возникают вопросы.
Возьму щас у тебя шаб куплю, запущу в +100500 потоков, и все пи...й накроется.:D
Не будет такого?
Да я их делаю так, как делают все. Один инстанс = 1 поток. Я просто не хочу сталкиваться с этими ошибками, которые возникают наподобие "перезагрузите браузер", если в 1 инстансе делать по 10+ потоков. Но в теории все это возможно было бы, если бы не глюки, которые выскакивали. Заметил это, когда в 20 потоков рекапчу разгадывал в ПМ, а потом вылезло сообщение в окне браузера, типа перезагрузите браузер.
А если работать без браузера, то тут зенка не нужна.
P.S. зато ресурсов жрет в 2 раза меньше, если работать в многопотоке в 1 инстансе
 
Последнее редактирование:

martens

Client
Регистрация
27.07.2015
Сообщения
97
Благодарностей
3
Баллы
8
Правильно я тут использовал функцию lock?
Мне нужно чтоб листы "pos" и "otp" лочились(для других потоков) на время поиска в них совпадения "id" и добавления его в список "pos"

var st = "";
var id = project.Variables["id"].Value;
int vr = 0;
lock(SyncObjects.ListSyncer)
{
var pos = project.Lists["pos"];
var otp = project.Lists["otp"];
int posc = pos.Count;
int otpc = otp.Count;
for (int i = 0; i < posc; i++)
{
st = pos;
if (st == id)
{
vr = 1;
i = posc;
}
}
if (vr == 0)
{
for (int i = 0; i < otpc; i++)
{
st = otp;
if (st == id)
{
vr = 1;
i = otpc;
}
}
}
if (vr == 0)
{
project.Lists["pos"].Add(id);
}
}
return vr;

Если я объявляю эти листы внутри функции "lock", так будет работать?
или нужно "var pos = project.Lists["pos"];" перед "lock" именно ставить?
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Правильно я тут использовал функцию lock?
Мне нужно чтоб листы "pos" и "otp" лочились(для других потоков) на время поиска в них совпадения "id" и добавления его в список "pos"

var st = "";
var id = project.Variables["id"].Value;
int vr = 0;
lock(SyncObjects.ListSyncer)
{
var pos = project.Lists["pos"];
var otp = project.Lists["otp"];
int posc = pos.Count;
int otpc = otp.Count;
for (int i = 0; i < posc; i++)
{
st = pos;
if (st == id)
{
vr = 1;
i = posc;
}
}
if (vr == 0)
{
for (int i = 0; i < otpc; i++)
{
st = otp;
if (st == id)
{
vr = 1;
i = otpc;
}
}
}
if (vr == 0)
{
project.Lists["pos"].Add(id);
}
}
return vr;

Если я объявляю эти листы внутри функции "lock", так будет работать?
или нужно "var pos = project.Lists["pos"];" перед "lock" именно ставить?
В таком варианте код вообще нечитабельный, на будущее старайся называть все переменные более-менее нормальными названиями, а то сам себе проблемы найдешь, когда придется исправлять данный участок кода. Для вставки кода на форуме есть спец функция (в Insert), туда его надо вставлять. По поводу твоего вопроса я бы просто сделал так, если переменная id не берется от одного из 2 листов (код не разбирал, так как у тебя там каша на данный момент):
Код:
lock(SyncObjects.ListSyncer)
{
      project.Lists["pos"].Add(id);
}
Остальное лочить нет толку, так как читать можно в любом количестве потоков. Но если у тебя твоя переменная id может изменяться сразу в несколько потоков (что вполне возможно), то придется лочить все (объявление листов можешь не добавлять в lock)
 
Последнее редактирование:
  • Спасибо
Реакции: martens

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
824
Баллы
93
А как эта блокировка выполняется? Только сниппетами я так понимаю.
Не только сниппетами, если ты стандартными экшенами делаешь взять/добавить/изментиь значение в списке, и при этом у тебя стоит галка нас "сохранить результаты", то и так все работает.
Все что описывалось, это если ты работаешь через C#. Тут надо самому заботиться о доступе к ресурсам в многопоточном шаблоне.

а я их делаю так, как делают все. Один инстанс = 1 поток. Я просто не хочу сталкиваться с этими ошибками, которые возникают наподобие "перезагрузите браузер", если в 1 инстансе делать по 10+ потоков.
Дружище, без обид, но ты гонишь хню. Ты уходишь от прямого вопроса, который я тебе задал.
Работают ли твои шаблоны в многопотоке, и как грамотно они отрабатывают данную ситуацию.
А где они работают это не важно, через бразуер, или через запросы.
Если ты этого не понимаешь(или не хочешь, уходя от прямого вопроса), то как ты вообще продаешь шабы и предлагаешь свои услуги?

Ты продаешь свои услуги популяризуя направление кодинга?
Так так и напиши, я дилетант, начал изучать C# продаю свои поделки, и научу вас этому за определенную мзду.:D
Опиши свой скилл, где учился и чего добился.

PS: Мне пох на твой скилл.:D
Но не вводи новорегов в заблуждение и C# экстаз используя кучу заумных слов, большую часть которых ты нахватался читая Шилдта или Троелсена, и так и не до конца понимая их суть(я делаю эти выводы исходя из того как ты описывал ссылочные и значимые типы, которые вообще были не в тему).
 
Последнее редактирование:
  • Спасибо
Реакции: doc и one

martens

Client
Регистрация
27.07.2015
Сообщения
97
Благодарностей
3
Баллы
8
В таком варианте код вообще нечитабельный, на будущее старайся называть все переменные более-менее нормальными названиями, а то сам себе проблемы найдешь, когда придется исправлять данный участок кода. Для вставки кода на форуме есть спец функция (в Insert), туда его надо вставлять. По поводу твоего вопроса я бы просто сделал так, если переменная id не берется от одного из 2 листов (код не разбирал, так как у тебя там каша на данный момент):
Код:
lock(SyncObjects.ListSyncer)
{
      project.Lists["pos"].Add(id);
}
Остальное лочить нет толку, так как читать можно в любом количестве потоков. Но если у тебя твоя переменная id может изменяться сразу в несколько потоков (что вполне возможно), то придется лочить все (объявление листов можешь не добавлять в lock)
Код:
var st = "";
var id = project.Variables["id"].Value;
int vr = 0;
lock(SyncObjects.ListSyncer)
{
   var pos = project.Lists["pos"];
   var otp = project.Lists["otp"];
    int posc = pos.Count;
    int otpc = otp.Count;
    for (int i = 0; i < posc; i++)
    {
        st = pos[i];
        if (st == id)
        {
            vr = 1;
            i = posc;
        }
    }
    if (vr == 0)
    {
        for (int i = 0; i < otpc; i++)
        {
            st = otp[i];
            if (st == id)
            {
                vr = 1;
                i = otpc;
            }
        }
    }
    if (vr == 0)
    {
        project.Lists["pos"].Add(id);
    }
}
return vr;
Вот читабельный вариант.
По моему, если в lock запихнуть только project.Lists["pos"].Add(id); тогда в моём случае теряется весь смысл lock.
Ведь если 2 потока начнут одновременно проверять на совпадение одинаковое значение, то сначала они это значение просто не найдут и далее оба добавят (последовательно) в список 2 раза это значение.
А должно быть так: первый поток должен это значение не найти - сразу добавить, а второй поток подождать пока закончит первый и увидеть, что значение уже добавлено.
 
  • Спасибо
Реакции: doc

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
824
Баллы
93
Вот читабельный вариант.
Читабельный вариант делается так.

C#:
var st = "";
var id = project.Variables["id"].Value;
int vr = 0;
lock(SyncObjects.ListSyncer)
{
   var pos = project.Lists["pos"];
   var otp = project.Lists["otp"];
    int posc = pos.Count;
    int otpc = otp.Count;
    for (int i = 0; i < posc; i++)
    {
        st = pos[i];
        if (st == id)
        {
            vr = 1;
            i = posc;
        }
    }
    if (vr == 0)
    {
        for (int i = 0; i < otpc; i++)
        {
            st = otp[i];
            if (st == id)
            {
                vr = 1;
                i = otpc;
            }
        }
    }
    if (vr == 0)
    {
        project.Lists["pos"].Add(id);
    }
}
return vr;

По моему, если в lock запихнуть только project.Lists["pos"].Add(id); тогда в моём случае теряется весь смысл lock.
Ведь если 2 потока начнут одновременно проверять на совпадение одинаковое значение, то сначала они это значение просто не найдут и далее оба добавят (последовательно) в список 2 раза это значение.
А должно быть так: первый поток должен это значение не найти - сразу добавить, а второй поток подождать пока закончит первый и увидеть, что значение уже добавлено.
Как раз в этом и есть смысл. Через lock мы делаем, что доступ к определенным ресурсам идет последовательно, по очереди.
Если касаемо данного куска кода, то пока не выполнится весь код внутри блока lock другой поток не может начать выполнение данного участка кода. Несколько потоков не могут "одновременнно" выполнять данный кусок кода.
Соответственно какой поток окажется "шустрее", тот и будет выполнять этот кусок кода, и работать с двумя списками.

Если не углубляться в детали, то ваша логика построена вполне вменяемо.
И не надо бояться этого
а второй поток подождать пока закончит первый и увидеть, что значение уже добавлено.
Каждый поток будет выполнять данный кусок кода по очереди. Вы уже сделали это, заключив доступ к двум спискам в lock.
Ваша задача, это чтобы внутри блока lock была адекватная логика по работе с двумя списками.

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

Хз, как бы стараюсь все по простому написать, насколько это возможно.:ds:
 
  • Спасибо
Реакции: martens

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Дружище, без обид, но ты гонишь хню. Ты уходишь от прямого вопроса, который я тебе задал.
Работают ли твои шаблоны в многопотоке, и как грамотно они отрабатывают данную ситуацию.
А где они работают это не важно, через бразуер, или через запросы.
Если ты этого не понимаешь(или не хочешь, уходя от прямого вопроса), то как ты вообще продаешь шабы и предлагаешь свои услуги?

Ты продаешь свои услуги популяризуя направление кодинга?
Так так и напиши, я дилетант, начал изучать C# продаю свои поделки, и научу вас этому за определенную мзду.:D
Опиши свой скилл, где учился и чего добился.

PS: Мне пох на твой скилл.:D
Но не вводи новорегов в заблуждение и C# экстаз используя кучу заумных слов, большую часть которых ты нахватался читая Шилдта или Троелсена, и так и не до конца понимая их суть(я делаю эти выводы исходя из того как ты описывал ссылочные и значимые типы, которые вообще были не в тему).
Мои шаблоны в многопотоке работали уже через неделю после того, как я купил зенку, так что не понимаю твоей сути вопроса о том, работают ли мои шаблоны в многопотоке, так как тут любой новичок практически может сделать их, выбрать количество потоков и запустить. Другое дело доступ к разделяемым ресурсам сделать, но и там не ядерная физика по сложности.
Я понимаю, если бы ты спросил, использую ли я пул потоков/таски для выполнения post/get запросов в многопоточности или TPL для расчета циклов.
 

prankbox

Client
Регистрация
03.08.2016
Сообщения
12
Благодарностей
1
Баллы
3
Я щас вообще практически не работаю с зенкой, учу c# не покладая рук, особенно занимаюсь SQL синтаксисом, начинаю понимать как работать с БД, Entity Framework и много другого, что по сравнению с зенкой сложнее в разы.
Смог к Зенке прикрутить Entity Framework?
 

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