Group.Wait()
блокируется до тех пор, пока не будут возвращены все вызовы функций из метода Group.Go()
, так что это точка синхронизации. Это гарантирует, что performAction(one, two)
не запустится до того, как будут выполнены записи в one
и two
, поэтому в вашем примере мьютекс не нужен.
g, gctx := errgroup.WithContext(ctx)
g.Go(func() error {
// ...
one = resp.One
return nil
})
g.Go(func() error {
// ...
two = resp.Two
return nil
})
if err := g.Wait(); err != nil {
return err
}
// Here you can access one and two safely:
performAction(one, two)
Если вы хотите получить доступ к one
и two
из других программ, в то время как программы, которые их пишут, работают одновременно, то да, вам нужно заблокировать их, например:
// This goroutine runs concurrently, so all concurrent access must be synchronized:
go func() {
mu.Lock()
fmt.Println(one, two)
mu.Unlock()
}()
g, gctx := errgroup.WithContext(ctx)
g.Go(func() error {
// ...
mu.Lock()
one = resp.One
mu.Unlock()
return nil
})
g.Go(func() error {
// ...
mu.Lock()
two = resp.Two
mu.Unlock()
return nil
})
if err := g.Wait(); err != nil {
return err
}
// Note that you don't need to lock here
// if the first concurrent goroutine only reads one and two.
performAction(one, two)
Также обратите внимание, что в приведенном выше примере вы можете использовать sync.RWMutex
, а в процедуре, которая их читает, RWMutex.RLock()
и RWMutex.RUnlock()
также достаточно. [1 119]
Если я понимаю вопрос, это намного легче, чем люди говорят - если Вы хотите позволить WebClient сделать все основные детали запроса (включая перенаправление), но затем получить фактический ответ URI в конце, можно разделить WebClient на подклассы как это:
class MyWebClient : WebClient
{
Uri _responseUri;
public Uri ResponseUri
{
get { return _responseUri; }
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
_responseUri = response.ResponseUri;
return response;
}
}
Просто используйте MyWebClient везде, Вы использовали бы WebClient. После совершения любого вызова WebClient, который необходимо было сделать, затем можно просто использовать ResponseUri для получения фактического перенаправленного URI. Необходимо было бы добавить подобное переопределение для GetWebResponse (запрос WebRequest, результат IAsyncResult) также при использовании асинхронного материала.
HttpWebRequest. AllowAutoRedirect может иметь значение false. Затем Вы имели бы к вручную кодам состояния HTTP в этих 300 диапазонах.
// Create a new HttpWebRequest Object to the mentioned URL.
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create("http://www.contoso.com");
myHttpWebRequest.MaximumAutomaticRedirections=1;
myHttpWebRequest.AllowAutoRedirect=true;
HttpWebResponse myHttpWebResponse=(HttpWebResponse)myHttpWebRequest.GetResponse();
С HttpWebRequest
, Вы установили бы AllowAutoRedirect
свойство к false
. Когда это произойдет, любой ответ с кодом состояния между 300-399 не будет автоматически перенаправлен.
Можно затем получить новый URL из заголовков ответа и затем создать новое HttpWebRequest
экземпляр к новому URL.
С WebClient
класс, я сомневаюсь, что можно изменить его out-of-the-box так, чтобы он не позволял перенаправления. То, что Вы могли сделать, получают класс из WebClient
класс и затем переопределяет GetWebRequest
и GetWebResponse
методы для изменения WebRequest
/WebResponse
экземпляры, которые возвращает базовое внедрение; если это HttpWebRequest
, затем установите AllowAutoRedirect
свойство к false
. На ответе, если код состояния находится в диапазоне 300-399, то выпускают новый запрос.
Однако я не знаю, что можно выпустить новый запрос из GetWebRequest
/GetWebResponse
методы, таким образом, могло бы быть лучше просто иметь цикл, который выполняется с HttpWebRequest
/HttpWebResponse
пока все перенаправления не сопровождаются.
Класс WebClient имеет опцию следовать за перенаправлениями. Набор, что опция и Вы должны быть в порядке.
Хорошо это действительно hackish, но ключ должен использовать HttpWebRequest и затем установить свойство AllowAutoRedirect на истинный.
Вот ОЧЕНЬ взломан вместе пример
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://tinyurl.com/dbysxp");
req.Method = "GET";
req.AllowAutoRedirect = true;
WebResponse response = req.GetResponse();
response.GetResponseStream();
Stream responseStream = response.GetResponseStream();
// Content-Length header is not trustable, but makes a good hint.
// Responses longer than int size will throw an exception here!
int length = (int)response.ContentLength;
const int bufSizeMax = 65536; // max read buffer size conserves memory
const int bufSizeMin = 8192; // min size prevents numerous small reads
// Use Content-Length if between bufSizeMax and bufSizeMin
int bufSize = bufSizeMin;
if (length > bufSize)
bufSize = length > bufSizeMax ? bufSizeMax : length;
StringBuilder sb;
// Allocate buffer and StringBuilder for reading response
byte[] buf = new byte[bufSize];
sb = new StringBuilder(bufSize);
// Read response stream until end
while ((length = responseStream.Read(buf, 0, buf.Length)) != 0)
sb.Append(Encoding.UTF8.GetString(buf, 0, length));
string source = sb.ToString();string title = Regex.Match(source,
@"\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)\</title\>",RegexOptions.IgnoreCase).Groups["Title"].Value;
enter code here