All streams
Search
Write a publication
Pull to refresh
4
0
Владислав @ghostiam

На Go писатель, серверов пинатель.

Send message
Как я понимаю, это что-то типо итога раздела, там ссылаются на ту же мысль, что с глобальной переменной было плохо, а без неё мы на вопросы
Вы можете изолированно тестировать её? Можете тестировать параллельно? Можете использовать одновременно несколько экземпляров?

можем ответить «Да», просто такое вполне может быть и в реальном проекте.

Например, далеко ходить не нужно, возьмём стандартную библиотеку net/http, и стандартный роутер для http сервера http.ServeMux.
Сделаем простой сервер (обработку ошибок опустим)
Код
package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
	go http.ListenAndServe(":3000", nil)
	go http.ListenAndServe(":3001", nil)

	select {}
}


В примере выше, зайдя на http://localhost:3000/hello и на http://localhost:3001/hello мы увидим одно и то же, так как http.HandleFunc по факту вызывает метод у глобальной переменной, а http.ListenAndServe при передаче вторым параметром nil её использует.
Хорошо ли это? Для прототипов, возможно, но это неявная «магия» и на вопросы выше уже не получится так однозначно ответить.
Но если мы сделаем тот же сервер с созданием нового роутера и передадим его явно, проблемы тут же исчезают:
Код
package main

import (
	"net/http"
)

func main() {
	r1 := http.NewServeMux()
	r1.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world 3000"))
	})
	
	r2:= http.NewServeMux()
	r2.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world 3001"))
	})
	
	go http.ListenAndServe(":3000", r1)
	go http.ListenAndServe(":3001", r2)

	select {}
}


И такое не редко встречается, но данный пример не так опасен, так как в данном случае мы смогли создать новый экземпляр который не повлияет на остальные, но ведь существуют библиотеки, которые хочется выполнять в разных горутинах или параллельно, но не получается, так как у неё объявлена важная глобальная переменная, которая влияет на все остальные вызовы этой библиотеки.
В статье речь была о проблеме с глобальной переменной count, а в примере с объектом всё хорошо, пока вы не вызываете метод Increment в разных горутинах.
Но и это починить не сильно сложно, просто добавь воды мьютекс или для счётчика можно использовать atomic (пришлось заменить int на int64, так как atomic умеет работать только с int32/uint32 и int64/uint64 указанными явно):
package counter

import (
	"sync"
	"sync/atomic"
)

type Counter struct {
	count int64
	mx    sync.Mutex
}

func (c *Counter) Increment(n int64) int64 {
	c.mx.Lock()
	defer c.mx.Unlock()

	c.count += n
	return c.count
}
func (c *Counter) IncrementAtomic(n int64) int64 {
	atomic.AddInt64(&c.count, n) 
	return atomic.LoadInt64(&c.count)
}

Для этого они просят указывать email при получении сертификата.
Мне недавно пришло письмо с указанием доменов, где находится старый certbot с сообщением, что надо бы обновить, так как старое апи будет отключено.
Не советую его использовать, если у вас разные файловые системы, одна case sensitive, а другая case insensitive.
Файлы теряются при переименовании. Сам так потерял кучу файлов, пока заметил ошибку.
Ошибке уже почти 5 лет и ничего сделать с этим не могут.
github.com/syncthing/syncthing/issues/1787#issuecomment-174102571
А на сколько реально делать на таких объёмах (от 8тб) soft RAID 1(mirror)? Или это только для задач долгосрочного хранения с дупликацией без raid?
Есть проект, где на пины, которые осталить от программатора, приделывают кнопку подтверждения.
Думаю, можно попробовать за программировать какой нибудь патерн для этой кнопки.
Я недавно разбирал мышь Logitech G403, колесо стало проскальзывать в пазах энкодера, подкладывал бумажку между штырём и пазом.
Так вот, там энкодер даёт ощущение щелчка при прокручивании, собственно так я и понял, что дело не в софте, а в железе.
А сколько потребляет сервер на xeon 5-10 летней давности? (Не могу нагуглить)
Я когда выбирал, чем бы заменить свою Orange PI(хотелось запускать что угодно, а не только то, что существует под ARM или в исходниках), по цене было почти рядом Б\У двухпроцессорный сервер 1U на Xeon(БП на 300 Вт) или новая маленькая коробочка на Атоме(TV Box). Выбор пал на второе из за расчётов мощности сервера 150-300 Вт (110-220КВт\ч в месяц, что равно 550-1100руб\мес). С тех пор(года два) коробочка на Атоме с HDD 3.5 во внешнем боксе + UPS потребляет 14Вт(10КВт\ч в месяц, что равно 50руб\мес).
Но желание, когда нибудь, приобрести настоящий сервер есть, но меня всё душат расчёты потребления и немного шум от 1U.

Я зарегистрирован 7 лет как и всё ещё 0, возможно это действительно только для полноправных участников.

В моей ленте практически нет NSFW блогов, но тем не менее авторы отчитываются в своей ленте о плохой работе алгоритма. Судя по всему, это приведёт к тому, что в день Х, очень много авторов будет забанено. Приходится, на всякий случай, подписываться на них на других сайтах.
Мы ведь можем использовать IP в качестве ID
Ответ?
1 — G
2 — J
3 — A
4 — F
5 — H
6 — C
7 — E
8 — B
9 — I
10 — D


Код №6 в виде текста :)
++++++++[>++++>++++++++++>+++++++++>++++++++++++++>+<<<<<-]>>.>.<.<.>>>++.+++.---------.-------.++++++++++++++.>++.

А как стоит поступить, если, к примеру, необходимо одновременно найти по Email и удалить?
Сделать дополнительный интерфейс, который будет это делать?
type RepositoryFindRemover interface {
	RepositoryFinderByEmail
	RepositoryRemover
}
Правильно ли я понимаю, что в случае примера с Repository
type (
	AMQPHandler struct {
		repository Repository
	}

	Repository interface {
		Add(user *User) error
		FindByID(ID string) (*User, error)
		FindByEmail(email string) (*User, error)
		FindByCountry(country string) (*User, error)
		FindByEmailAndCountry(country string) (*User, error)
		Search(...CriteriaOption) ([]*User, error)
		Remove(ID string) error
		// и еще
		// и еще
		// и еще
		// ...
	}
)

Я должен буду преобразовать интерфейс в такие интерфейсы?
type (
	AMQPHandler struct {
		repository Repository
	}

	Repository interface {
		RepositoryAdder
		RepositoryFinderByID
		RepositoryFinderByEmail
		RepositoryFinderByCountry
		RepositoryFinderByEmailAndCountry
		RepositorySearcher
		RepositoryRemover
		// и еще
		// и еще
		// и еще
		// ...
	}

	RepositoryAdder interface {
		Add(user *User) error
	}
	
	RepositoryFinderByID interface {
		FindByID(ID string) (*User, error)
	}
	
	RepositoryFinderByEmail interface {
		FindByEmail(email string) (*User, error)
	}
	
	RepositoryFinderByCountry interface {
		FindByCountry(country string) (*User, error)
	}
	
	RepositoryFinderByEmailAndCountry interface {
		FindByEmailAndCountry(country string) (*User, error)
	}
	
	RepositorySearcher interface {
		Search(...CriteriaOption) ([]*User, error)
	}
	
	RepositoryRemover interface {
		Remove(ID string) error
	}
)
Я использую для закрытых проектов Gogs. Нравится его простота установки и простой интерфейс.
Протестировал. Состояния прекрасно работают из кода.

public Page() {
            var stateContainer = new StateContainer();
            stateContainer.SetBinding(StateContainer.StateProperty, "State");

            stateContainer.Conditions.Add(new StateCondition { State = "Loading", Content = new ActivityIndicator { IsRunning = true } });
            stateContainer.Conditions.Add(new StateCondition { State = "Normal", Content = new Label { Text = "Данные загружены и можем их отобразить" } });

            ...

            Content = stateContainer;

            BindingContext = this;
        }
Некоторые провайдеры, например Ростелеком, блокируют доступ по этим портам в своих сетях, что довольно мило с их стороны.


Боюсь что это не так…
Скрин
image
2

Information

Rating
Does not participate
Registered
Activity