powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Впечатления от собеседования (связано с .Net)
25 сообщений из 83, страница 1 из 4
Впечатления от собеседования (связано с .Net)
    #39466682
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На днях ходил на встречу, где был заданы всего два вопроса:
автор1) Что Вам не нравится в приведенном коде:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
private readonly Dictionary<string, Guid> dict = new Dictionary<string, Guid>();

public Guid GetValue(stringkey)
{
    if (dict.ContainsKey(key))
        return dict[key];
    var newValue = Guid.NewGuid();
    dict.Add(key, newValue);
    return newValue;
}


автор2) Как организовать доступ к объекту (dict, из примера выше, надо поправить тело метода GetValue) несколькими потоками?
Ответ на первый вопрос заключался в том, что вместо
Код: c#
1.
2.
if (dict.ContainsKey(key))
    return dict[key];


нужно использовать
Код: c#
1.
2.
3.
Guid value;
if (dict.TryGetValue(key, out value))
    return dict[key];


Если честно, я всегда использовал 1й вариант и по 2му у меня какие-то сомнения возникли, я не понял выгоды, чем 1й вариант, хуже 2го. Написал небольшую утилиту чтобы проверить время выполнения первого и второго куска. В словарь было добавлено 40 млн записей, разницы в производительности никакой, вообще. Возможно на слабом железе что-то и проявится, но в моем случае поиск в обоих случаях выполняется за одинаковое кол-во временных единиц. Кто-то может объяснить преимущество одного варианта над другим?
По второму вопросу ответ дам чуть позже, хочется услышать ваши решения. Я так же озвучу, какой вариант я предложил. Он был неправильным, мне сказали, что существует только одно решение задачи.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466700
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИМХО первый вариант от второго ничем не отличается. Два поиска key в dict
Может правильно все-таки
Код: c#
1.
2.
3.
Guid value;
if (dict.TryGetValue(key, out value))
    return value;


так один поиск будет.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466703
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TИМХО первый вариант от второго ничем не отличается. Два поиска key в dict
Может правильно все-таки
Код: c#
1.
2.
3.
Guid value;
if (dict.TryGetValue(key, out value))
    return value;


так один поиск будет.
да, value. Это очепятка, код тут набивал
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466709
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_Пав,

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
public bool ContainsKey(TKey key)
{
	return this.FindEntry(key) >= 0;
}

public bool TryGetValue(TKey key, out TValue value)
{
	int num = this.FindEntry(key);
	if (num >= 0)
	{
		value = this.entries[num].value;
		return true;
	}
	value = default(TValue);
	return false;
}


как видишь, разница по сути 0вая, просто с TryGetValue код "удобочитамее". Но как по мне, пофигу вообще, не принципиально.
хотя с учётом современных версий C# код должен выглядеть след. образом:
Код: c#
1.
2.
            if (dict.TryGetValue(key, out Guid value))
                return value;


+ если данный в многопоточной среде лучше не применять
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466713
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот результат поиска
GetValueI start at:06-06-2017 10:14:26.330
Guid = 0df051e7-c221-468b-aca6-85f514a723dd
GetValueI end at:06-06-2017 10:14:26.332

GetValueII start at:06-06-2017 10:14:26.333
Guid = 0df051e7-c221-468b-aca6-85f514a723dd
GetValueII end at:06-06-2017 10:14:26.333
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:14:35.483
Guid = 9b88cf75-64fa-4297-98e8-00a85cf67863
GetValueI end at:06-06-2017 10:14:35.484

GetValueII start at:06-06-2017 10:14:35.484
Guid = 9b88cf75-64fa-4297-98e8-00a85cf67863
GetValueII end at:06-06-2017 10:14:35.484
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:14:36.459
Guid = 4b0b3251-32ad-4f94-857a-9185635aedbe
GetValueI end at:06-06-2017 10:14:36.460

GetValueII start at:06-06-2017 10:14:36.460
Guid = 4b0b3251-32ad-4f94-857a-9185635aedbe
GetValueII end at:06-06-2017 10:14:36.460
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:14:37.499
Guid = 40f25a6f-5e68-496d-9e68-b7aca8e02a71
GetValueI end at:06-06-2017 10:14:37.500

GetValueII start at:06-06-2017 10:14:37.500
Guid = 40f25a6f-5e68-496d-9e68-b7aca8e02a71
GetValueII end at:06-06-2017 10:14:37.501
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:14:38.620
Guid = 929bd12d-bd1f-4d8e-8d0a-1e87e981c14b
GetValueI end at:06-06-2017 10:14:38.621

GetValueII start at:06-06-2017 10:14:38.622
Guid = 929bd12d-bd1f-4d8e-8d0a-1e87e981c14b
GetValueII end at:06-06-2017 10:14:38.623
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:14:39.445
Guid = 53144be1-66f3-4266-bcda-9fb7acb00086
GetValueI end at:06-06-2017 10:14:39.446

GetValueII start at:06-06-2017 10:14:39.448
Guid = 53144be1-66f3-4266-bcda-9fb7acb00086
GetValueII end at:06-06-2017 10:14:39.448
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:14:40.630
Guid = 061bcf94-3bdb-4fc8-b100-2220f0c8547f
GetValueI end at:06-06-2017 10:14:40.631

GetValueII start at:06-06-2017 10:14:40.632
Guid = 061bcf94-3bdb-4fc8-b100-2220f0c8547f
GetValueII end at:06-06-2017 10:14:40.632
Continue test? (Y/N) :>Y

GetValueI start at:06-06-2017 10:15:16.180
Guid = 07587b42-2937-4d01-afbb-27efa1f61059
GetValueI end at:06-06-2017 10:15:16.180

GetValueII start at:06-06-2017 10:15:16.181
Guid = 07587b42-2937-4d01-afbb-27efa1f61059
GetValueII end at:06-06-2017 10:15:16.182
Continue test? (Y/N) :>N
Press Enter

GetValueI - это первый вариант поиска, GetValueII - это второй. Как видно, разницы нет
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466718
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_Пававтор2) Как организовать доступ к объекту (dict, из примера выше, надо поправить тело метода GetValue) несколькими потоками?
Блокировкой
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
private readonly Dictionary<string, Guid> dict = new Dictionary<string, Guid>();

public Guid GetValue(stringkey)
{
 lock(dict) {
    if (dict.ContainsKey(key))
        return dict[key];
    var newValue = Guid.NewGuid();
    dict.Add(key, newValue);
    return newValue;
 }
}
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466722
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesудобочитамее
по мне, так дело вкуса. Мне больше первый вариант нравится: проверил, выполнил. Во втором случает лишняя переменная появляется. Имхо, дело вкуса.
Я просто под небольшим впечатлением от того, что мне говорили, мол второй вариант лучше.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466723
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСупер_Павпропущено...

Блокировкой
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
private readonly Dictionary<string, Guid> dict = new Dictionary<string, Guid>();

public Guid GetValue(stringkey)
{
 lock(dict) {
    if (dict.ContainsKey(key))
        return dict[key];
    var newValue = Guid.NewGuid();
    dict.Add(key, newValue);
    return newValue;
 }
}


Это был мой вариант. Блокировка им не понравилась.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466732
Pallaris
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В первом варианте метод GetValue меняет состояние коллекции, что печально. Либо переназвать, либо не добавлять элемент в коллекцию
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466733
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_ПавGetValueI - это первый вариант поиска, GetValueII - это второй. Как видно, разницы нет
Кривой замер. Чтобы разницу заметить общее время теста должно быть хотя бы сотни миллисекунд, лучше несколько секунд.

Также вопрос какие значения искались, если GetValue() вызывалось каждый с новым значением, т.е. происходило добавление, то разницы не будет.

Как уже написал - разница в количестве поисков по dict
Код: c#
1.
2.
    if (dict.ContainsKey(key)) // Первый поиск
        return dict[key];  // Второй поиск


Код: c#
1.
2.
if (dict.TryGetValue(key, out value)) // Первый поиск
    return value;
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466743
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСупер_ПавGetValueI - это первый вариант поиска, GetValueII - это второй. Как видно, разницы нет
Кривой замер. Чтобы разницу заметить общее время теста должно быть хотя бы сотни миллисекунд, лучше несколько секунд.

Также вопрос какие значения искались, если GetValue() вызывалось каждый с новым значением, т.е. происходило добавление, то разницы не будет.

Как уже написал - разница в количестве поисков по dict
Код: c#
1.
2.
    if (dict.ContainsKey(key)) // Первый поиск
        return dict[key];  // Второй поиск


Код: c#
1.
2.
if (dict.TryGetValue(key, out value)) // Первый поиск
    return value;


Разница понятна, но по мне, так оба варианта приемлемы. Не могу понять, зачем об этом спрашивать, коль 2 вариант правильные.
GetValueI и GetValueII вызывались с одним ключом по разу, ключе менялся, снова был вызов. Я не вижу смысла менять замер, коль разницы нет, оба куска кода отрабатывают очень быстро.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466745
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По поводу второго вопроса. lock забраковали, мол блокирует потоки. Единственное решение задачи - это класс ReaderWriterLockSlim
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466762
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,
авторКак уже написал - разница в количестве поисков по dict
дануна....
по кишкам имхо однохуйственно ( гляньте ктнонитьрефлекторм)
первый имхо даже живее будет ?
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466770
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степиDima T,
авторКак уже написал - разница в количестве поисков по dict
дануна....
Кишки уже привели выше 20543115
в дополнение
Код: c#
1.
2.
3.
4.
5.
        public TValue this[TKey key] {
            get {
                int i = FindEntry(key);
                if (i >= 0) return entries[i].value;
...


два вызова FindEntry() для исходного кода и один для TryGetValue()
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466778
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TГде-то в степиDima T,
пропущено...

дануна....
Кишки уже привели выше 20543115
в дополнение
Код: c#
1.
2.
3.
4.
5.
        public TValue this[TKey key] {
            get {
                int i = FindEntry(key);
                if (i >= 0) return entries[i].value;
...


два вызова FindEntry() для исходного кода и один для TryGetValue()
Не могу понять Вас, вы просто объясняете различия или утверждаете, что второй способ лучше?
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466786
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_ПавDima Tпропущено...

Кишки уже привели выше 20543115
в дополнение
Код: c#
1.
2.
3.
4.
5.
        public TValue this[TKey key] {
            get {
                int i = FindEntry(key);
                if (i >= 0) return entries[i].value;
...


два вызова FindEntry() для исходного кода и один для TryGetValue()
Не могу понять Вас, вы просто объясняете различия или утверждаете, что второй способ лучше?
Второй - быстрее, т.к. поиск (вызов FindEntry()) достаточно тяжелая операция.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466789
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСупер_Павпропущено...

Не могу понять Вас, вы просто объясняете различия или утверждаете, что второй способ лучше?
Второй - быстрее, т.к. поиск (вызов FindEntry()) достаточно тяжелая операция.
А я утверждаю, что нет разницы. Проверил на 40 млн записях.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466793
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,
тогда да, но надо смотреть чистый код, имхо в первом случае оптимизатор может порвать этот примитив на раз с двумя вызовами -
хотя к делу мало относится.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466836
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesпросто с TryGetValue код "удобочитамее"
код с параметрами out - сомнительная удобночитаемость
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466843
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_ПавDima Tпропущено...

Второй - быстрее, т.к. поиск (вызов FindEntry()) достаточно тяжелая операция.
А я утверждаю, что нет разницы. Проверил на 40 млн записях.
Хреново ты проверял
Исходник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
namespace Test {

	class TestDict {
		private readonly Dictionary<string, Guid> dict = new Dictionary<string, Guid>();

		public Guid GetValue1(string key)
		{
			if (dict.ContainsKey(key))
				return dict[key];
			var newValue = Guid.NewGuid();
			dict.Add(key, newValue);
			return newValue;
		}

		public Guid GetValue2(string key)
		{
			Guid value;
			if (dict.TryGetValue(key, out value))
				return value;
			var newValue = Guid.NewGuid();
			dict.Add(key, newValue);
			return newValue;
		}
	}

	static class Test {

		static string[] test_value;

		static void Init(int size) {
			Console.WriteLine($"Init {size} values");
			test_value = new string[size];
			for(int i = 0; i < test_value.Length; i++) test_value[i] = Guid.NewGuid().ToString();
		}

		static void Test1() {
			var td = new TestDict();
			Console.WriteLine("Test GetValue1() ...");
			var sw = Stopwatch.StartNew();
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue1(test_value[j]);
				}
			}
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Test2() {
			var td = new TestDict();
			Console.WriteLine("Test GetValue2() ...");
			var sw = Stopwatch.StartNew();
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue2(test_value[j]);
				}
			}
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Main(string[] args) {
			Init(100000);
			Test1();
			Test2();
			return;
		}
	}
}


Результат
Код: plaintext
1.
2.
3.
4.
Init 100000 values
Test GetValue1() ...
Elapsed 5721 ms
Test GetValue2() ...
Elapsed 4039 ms

Второй вариант на 30% быстрее.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466846
Фотография Cat2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Если несколько потоков, то надо использовать ConcurrentDictionary
https://msdn.microsoft.com/ru-ru/library/dd287191(v=vs.110).aspx
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466940
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСупер_Павпропущено...

А я утверждаю, что нет разницы. Проверил на 40 млн записях.
Хреново ты проверял
Исходник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
namespace Test {

	class TestDict {
		private readonly Dictionary<string, Guid> dict = new Dictionary<string, Guid>();

		public Guid GetValue1(string key)
		{
			if (dict.ContainsKey(key))
				return dict[key];
			var newValue = Guid.NewGuid();
			dict.Add(key, newValue);
			return newValue;
		}

		public Guid GetValue2(string key)
		{
			Guid value;
			if (dict.TryGetValue(key, out value))
				return value;
			var newValue = Guid.NewGuid();
			dict.Add(key, newValue);
			return newValue;
		}
	}

	static class Test {

		static string[] test_value;

		static void Init(int size) {
			Console.WriteLine($"Init {size} values");
			test_value = new string[size];
			for(int i = 0; i < test_value.Length; i++) test_value[i] = Guid.NewGuid().ToString();
		}

		static void Test1() {
			var td = new TestDict();
			Console.WriteLine("Test GetValue1() ...");
			var sw = Stopwatch.StartNew();
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue1(test_value[j]);
				}
			}
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Test2() {
			var td = new TestDict();
			Console.WriteLine("Test GetValue2() ...");
			var sw = Stopwatch.StartNew();
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue2(test_value[j]);
				}
			}
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Main(string[] args) {
			Init(100000);
			Test1();
			Test2();
			return;
		}
	}
}


Результат
Код: plaintext
1.
2.
3.
4.
Init 100000 values
Test GetValue1() ...
Elapsed 5721 ms
Test GetValue2() ...
Elapsed 4039 ms

Второй вариант на 30% быстрее.
Хорош. Вы суммарное время работы со 100к элементов указали, разница в 1.5 секунды не впечатляет.
А если сперва заполнить словари (о чем говорилось на собеседовании, было условие, что 99% записей существуют в словаре), то поиск не отличается.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
class Program
{
    private static readonly TestClass TestClass1 = new TestClass();
    private static readonly TestClass TestClass2 = new TestClass();
    private static void Main()
    {
        const int count = 10000000;
        for (var i = 0; i < count; i++)
        {
            StartTest1(i);
            StartTest2(i);
        }

        Console.WriteLine("Press Enter");
        Console.ReadLine();
    }

    private static void StartTest1(int key)
    {
        var sw = Stopwatch.StartNew();
        TestClass1.GetValueI(key);
        var ms = sw.ElapsedMilliseconds;

        if (ms > 100)
        {
            Console.WriteLine($"Key: {key}");
            Console.WriteLine($"GetValueI: {ms} ms.");
            Console.WriteLine();
        }
    }

    private static void StartTest2(int key)
    {
        var sw = Stopwatch.StartNew();
        TestClass2.GetValueI(key);
        var ms = sw.ElapsedMilliseconds;

        if (ms > 100)
        {
            Console.WriteLine($"Key: {key}");
            Console.WriteLine($"GetValueII: {ms} ms.");
            Console.WriteLine();
        }
    }
}

class TestDict
{
    private readonly Dictionary<string, Guid> dict = new Dictionary<string, Guid>();

    public Guid GetValue1(string key)
    {
        if (dict.ContainsKey(key))
            return dict[key];
        var newValue = Guid.NewGuid();
        dict.Add(key, newValue);
        return newValue;
    }

    public Guid GetValue2(string key)
    {
        Guid value;
        if (dict.TryGetValue(key, out value))
            return value;
        var newValue = Guid.NewGuid();
        dict.Add(key, newValue);
        return newValue;
    }
}

...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466941
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_ПавПо поводу второго вопроса. lock забраковали, мол блокирует потоки. Единственное решение задачи - это класс ReaderWriterLockSlim
Блокирует не надолго, поэтому засомневался что тут поможет ReaderWriterLockSlim, RW блокировки на самом деле достаточно тормозные.
Делал по примеру из хэлпа .
Исходник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
namespace Test {

	class TestDict {
		private Dictionary<string, Guid> dict;

		ReaderWriterLockSlim rwsl = new ReaderWriterLockSlim();

		public void Init() {
			dict = new Dictionary<string, Guid>();
		}

		public Guid GetValue_lock(string key)
		{
			lock(dict) {
				Guid value;
				if (dict.TryGetValue(key, out value))
					return value;
				var newValue = Guid.NewGuid();
				dict.Add(key, newValue);
				return newValue;
			}
		}

		public Guid GetValue_RWSL(string key)
		{
			rwsl.EnterUpgradeableReadLock();
			try {
				Guid value;
				if (dict.TryGetValue(key, out value)) {
					return value;
				}
				rwsl.EnterWriteLock();
				try {
					var newValue = Guid.NewGuid();
					dict.Add(key, newValue);
					return newValue;
				} finally {
					rwsl.ExitWriteLock();
				}
			} finally {
				rwsl.ExitUpgradeableReadLock();
			}
		}
	}

	class TestDictConcurrent {
		private ConcurrentDictionary<string, Guid> dict = new ConcurrentDictionary<string, Guid>();

		public Guid GetValue(string key)
		{
			return dict.GetOrAdd(key, (k) => Guid.NewGuid());
		}
	}

	static class Test {

		static string[] test_value;

		static void Init(int size) {
			Console.WriteLine($"Init {size} values");
			test_value = new string[size];
			for(int i = 0; i < test_value.Length; i++) test_value[i] = Guid.NewGuid().ToString();
		}

		static TestDict td = new TestDict();

		static void Task1() {
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue_lock(test_value[j]);
				}
			}
		}

		static void Test1() {
			td.Init();
			Console.WriteLine("Test lock() ...");
			var sw = Stopwatch.StartNew();
			var tasks = new Task[3];
			for(int i = 0; i < tasks.Length; i++) {
				tasks[i] = Task.Run(() => Task1());
			}
			Task.WaitAll(tasks);
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Task2() {
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue_RWSL(test_value[j]);
				}
			}
		}

		static void Test2() {
			td.Init();
			Console.WriteLine("Test ReaderWriterLockSlim() ...");
			var sw = Stopwatch.StartNew();
			var tasks = new Task[3];
			for(int i = 0; i < tasks.Length; i++) {
				tasks[i] = Task.Run(() => Task2());
			}
			Task.WaitAll(tasks);
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static TestDictConcurrent tdc = new TestDictConcurrent();

		static void Task3() {
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = tdc.GetValue(test_value[j]);
				}
			}
		}

		static void Test3() {
			td.Init();
			Console.WriteLine("Test ConcurrentDictionary() ...");
			var sw = Stopwatch.StartNew();
			var tasks = new Task[3];
			for(int i = 0; i < tasks.Length; i++) {
				tasks[i] = Task.Run(() => Task3());
			}
			Task.WaitAll(tasks);
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Main(string[] args) {
			Init(100000);
			Test1();
			Test2();
			Test3();
			return;
		}
	}
}


Результат
Код: plaintext
1.
2.
3.
4.
5.
6.
Init 100000 values
Test lock() ...
Elapsed 13309 ms
Test ReaderWriterLockSlim() ...
Elapsed 16477 ms
Test ConcurrentDictionary() ...
Elapsed 4922 ms

lock() на 20% быстрее оказался.
И как правильно замечено выше: надо использовать ConcurrentDictionary(), но в той постановке вопроса это не разрешается.
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466943
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Супер_ПавОтвет на первый вопрос заключался в том, что вместо
Код: c#
1.
2.
if (dict.ContainsKey(key))
    return dict[key];


нужно использовать
Код: c#
1.
2.
3.
Guid value;
if (dict.TryGetValue(key, out value))
    return dict[key];



Молотком по пальцам таким собеседователям.
Логика разная у кода, второй всегда что то вернет, как минимум default(Guid).
...
Рейтинг: 0 / 0
Впечатления от собеседования (связано с .Net)
    #39466953
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСупер_ПавПо поводу второго вопроса. lock забраковали, мол блокирует потоки. Единственное решение задачи - это класс ReaderWriterLockSlim
Блокирует не надолго, поэтому засомневался что тут поможет ReaderWriterLockSlim, RW блокировки на самом деле достаточно тормозные.
Делал по примеру из хэлпа .
Исходник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
namespace Test {

	class TestDict {
		private Dictionary<string, Guid> dict;

		ReaderWriterLockSlim rwsl = new ReaderWriterLockSlim();

		public void Init() {
			dict = new Dictionary<string, Guid>();
		}

		public Guid GetValue_lock(string key)
		{
			lock(dict) {
				Guid value;
				if (dict.TryGetValue(key, out value))
					return value;
				var newValue = Guid.NewGuid();
				dict.Add(key, newValue);
				return newValue;
			}
		}

		public Guid GetValue_RWSL(string key)
		{
			rwsl.EnterUpgradeableReadLock();
			try {
				Guid value;
				if (dict.TryGetValue(key, out value)) {
					return value;
				}
				rwsl.EnterWriteLock();
				try {
					var newValue = Guid.NewGuid();
					dict.Add(key, newValue);
					return newValue;
				} finally {
					rwsl.ExitWriteLock();
				}
			} finally {
				rwsl.ExitUpgradeableReadLock();
			}
		}
	}

	class TestDictConcurrent {
		private ConcurrentDictionary<string, Guid> dict = new ConcurrentDictionary<string, Guid>();

		public Guid GetValue(string key)
		{
			return dict.GetOrAdd(key, (k) => Guid.NewGuid());
		}
	}

	static class Test {

		static string[] test_value;

		static void Init(int size) {
			Console.WriteLine($"Init {size} values");
			test_value = new string[size];
			for(int i = 0; i < test_value.Length; i++) test_value[i] = Guid.NewGuid().ToString();
		}

		static TestDict td = new TestDict();

		static void Task1() {
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue_lock(test_value[j]);
				}
			}
		}

		static void Test1() {
			td.Init();
			Console.WriteLine("Test lock() ...");
			var sw = Stopwatch.StartNew();
			var tasks = new Task[3];
			for(int i = 0; i < tasks.Length; i++) {
				tasks[i] = Task.Run(() => Task1());
			}
			Task.WaitAll(tasks);
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Task2() {
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = td.GetValue_RWSL(test_value[j]);
				}
			}
		}

		static void Test2() {
			td.Init();
			Console.WriteLine("Test ReaderWriterLockSlim() ...");
			var sw = Stopwatch.StartNew();
			var tasks = new Task[3];
			for(int i = 0; i < tasks.Length; i++) {
				tasks[i] = Task.Run(() => Task2());
			}
			Task.WaitAll(tasks);
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static TestDictConcurrent tdc = new TestDictConcurrent();

		static void Task3() {
			for(int i = 0; i < test_value.Length; i++) {
				for(int j = i; j < test_value.Length; j += 100) {
					var guid = tdc.GetValue(test_value[j]);
				}
			}
		}

		static void Test3() {
			td.Init();
			Console.WriteLine("Test ConcurrentDictionary() ...");
			var sw = Stopwatch.StartNew();
			var tasks = new Task[3];
			for(int i = 0; i < tasks.Length; i++) {
				tasks[i] = Task.Run(() => Task3());
			}
			Task.WaitAll(tasks);
			Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds} ms");
		}

		static void Main(string[] args) {
			Init(100000);
			Test1();
			Test2();
			Test3();
			return;
		}
	}
}


Результат
Код: plaintext
1.
2.
3.
4.
5.
6.
Init 100000 values
Test lock() ...
Elapsed 13309 ms
Test ReaderWriterLockSlim() ...
Elapsed 16477 ms
Test ConcurrentDictionary() ...
Elapsed 4922 ms

lock() на 20% быстрее оказался.
И как правильно замечено выше: надо использовать ConcurrentDictionary(), но в той постановке вопроса это не разрешается.

Ничего с потолка не взял. О чем сказали на собеседовании, то и привел. Я обычно забываю такие встречи, но тут прям сомнения закрались, что мне воду в уши льют. Удивило еще, что обошлись одним вопросом.
Вакансию нашел в разделе Вакансии сего сайта
...
Рейтинг: 0 / 0
25 сообщений из 83, страница 1 из 4
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Впечатления от собеседования (связано с .Net)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]