Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a dokumentum bemutatja, hogyan hajthat végre műveletet az JoinBlock<T1,T2> osztály használatával, ha az adatok több forrásból érhetők el. Azt is bemutatja, hogyan használható a nem mohó mód arra, hogy több összekapcsolási blokkot is lehetővé tegye az adatforrások hatékonyabb megosztásához.
Feljegyzés
A TPL-adatfolyamtár (a System.Threading.Tasks.Dataflow névtér) nincs elosztva a .NET-tel. Ha telepíteni szeretné a névteret a System.Threading.Tasks.Dataflow Visual Studióban, nyissa meg a projektet, válassza a Project menü NuGet-csomagok kezelése parancsát, és keressen rá online a System.Threading.Tasks.Dataflow csomagra. Másik lehetőségként futtassa dotnet add package System.Threading.Tasks.Dataflowa .NET Core parancssori felülettel való telepítéshez.
Példa
Az alábbi példa három erőforrástípust határoz meg, NetworkResourceFileResourceés MemoryResourceműveleteket hajt végre, amikor az erőforrások elérhetővé válnak. Ebben a példában az első művelet végrehajtásához és NetworkResource a második művelet FileResource végrehajtásához egy és MemoryResource MemoryResource pár szükséges. Ha engedélyezni szeretné ezeknek a műveleteknek a végrehajtását, amikor az összes szükséges erőforrás elérhető, ez a példa az osztályt JoinBlock<T1,T2> használja. Amikor egy JoinBlock<T1,T2> objektum minden forrásból fogad adatokat, propagálja az adatokat a célnak, amely ebben a példában egy ActionBlock<TInput> objektum. Mindkét JoinBlock<T1,T2> objektum egy megosztott objektumkészletből MemoryResource olvas be.
using System;
using System.Threading;
using System.Threading.Tasks.Dataflow;
// Demonstrates how to use non-greedy join blocks to distribute
// resources among a dataflow network.
class Program
{
// Represents a resource. A derived class might represent
// a limited resource such as a memory, network, or I/O
// device.
abstract class Resource
{
}
// Represents a memory resource. For brevity, the details of
// this class are omitted.
class MemoryResource : Resource
{
}
// Represents a network resource. For brevity, the details of
// this class are omitted.
class NetworkResource : Resource
{
}
// Represents a file resource. For brevity, the details of
// this class are omitted.
class FileResource : Resource
{
}
static void Main(string[] args)
{
// Create three BufferBlock<T> objects. Each object holds a different
// type of resource.
var networkResources = new BufferBlock<NetworkResource>();
var fileResources = new BufferBlock<FileResource>();
var memoryResources = new BufferBlock<MemoryResource>();
// Create two non-greedy JoinBlock<T1, T2> objects.
// The first join works with network and memory resources;
// the second pool works with file and memory resources.
var joinNetworkAndMemoryResources =
new JoinBlock<NetworkResource, MemoryResource>(
new GroupingDataflowBlockOptions
{
Greedy = false
});
var joinFileAndMemoryResources =
new JoinBlock<FileResource, MemoryResource>(
new GroupingDataflowBlockOptions
{
Greedy = false
});
// Create two ActionBlock<T> objects.
// The first block acts on a network resource and a memory resource.
// The second block acts on a file resource and a memory resource.
var networkMemoryAction =
new ActionBlock<Tuple<NetworkResource, MemoryResource>>(
data =>
{
// Perform some action on the resources.
// Print a message.
Console.WriteLine("Network worker: using resources...");
// Simulate a lengthy operation that uses the resources.
Thread.Sleep(new Random().Next(500, 2000));
// Print a message.
Console.WriteLine("Network worker: finished using resources...");
// Release the resources back to their respective pools.
networkResources.Post(data.Item1);
memoryResources.Post(data.Item2);
});
var fileMemoryAction =
new ActionBlock<Tuple<FileResource, MemoryResource>>(
data =>
{
// Perform some action on the resources.
// Print a message.
Console.WriteLine("File worker: using resources...");
// Simulate a lengthy operation that uses the resources.
Thread.Sleep(new Random().Next(500, 2000));
// Print a message.
Console.WriteLine("File worker: finished using resources...");
// Release the resources back to their respective pools.
fileResources.Post(data.Item1);
memoryResources.Post(data.Item2);
});
// Link the resource pools to the JoinBlock<T1, T2> objects.
// Because these join blocks operate in non-greedy mode, they do not
// take the resource from a pool until all resources are available from
// all pools.
networkResources.LinkTo(joinNetworkAndMemoryResources.Target1);
memoryResources.LinkTo(joinNetworkAndMemoryResources.Target2);
fileResources.LinkTo(joinFileAndMemoryResources.Target1);
memoryResources.LinkTo(joinFileAndMemoryResources.Target2);
// Link the JoinBlock<T1, T2> objects to the ActionBlock<T> objects.
joinNetworkAndMemoryResources.LinkTo(networkMemoryAction);
joinFileAndMemoryResources.LinkTo(fileMemoryAction);
// Populate the resource pools. In this example, network and
// file resources are more abundant than memory resources.
networkResources.Post(new NetworkResource());
networkResources.Post(new NetworkResource());
networkResources.Post(new NetworkResource());
memoryResources.Post(new MemoryResource());
fileResources.Post(new FileResource());
fileResources.Post(new FileResource());
fileResources.Post(new FileResource());
// Allow data to flow through the network for several seconds.
Thread.Sleep(10000);
}
}
/* Sample output:
File worker: using resources...
File worker: finished using resources...
Network worker: using resources...
Network worker: finished using resources...
File worker: using resources...
File worker: finished using resources...
Network worker: using resources...
Network worker: finished using resources...
File worker: using resources...
File worker: finished using resources...
File worker: using resources...
File worker: finished using resources...
Network worker: using resources...
Network worker: finished using resources...
Network worker: using resources...
Network worker: finished using resources...
File worker: using resources...
*/
Imports System.Threading
Imports System.Threading.Tasks.Dataflow
' Demonstrates how to use non-greedy join blocks to distribute
' resources among a dataflow network.
Friend Class Program
' Represents a resource. A derived class might represent
' a limited resource such as a memory, network, or I/O
' device.
Private MustInherit Class Resource
End Class
' Represents a memory resource. For brevity, the details of
' this class are omitted.
Private Class MemoryResource
Inherits Resource
End Class
' Represents a network resource. For brevity, the details of
' this class are omitted.
Private Class NetworkResource
Inherits Resource
End Class
' Represents a file resource. For brevity, the details of
' this class are omitted.
Private Class FileResource
Inherits Resource
End Class
Shared Sub Main(ByVal args() As String)
' Create three BufferBlock<T> objects. Each object holds a different
' type of resource.
Dim networkResources = New BufferBlock(Of NetworkResource)()
Dim fileResources = New BufferBlock(Of FileResource)()
Dim memoryResources = New BufferBlock(Of MemoryResource)()
' Create two non-greedy JoinBlock<T1, T2> objects.
' The first join works with network and memory resources;
' the second pool works with file and memory resources.
Dim joinNetworkAndMemoryResources = New JoinBlock(Of NetworkResource, MemoryResource)(New GroupingDataflowBlockOptions With {.Greedy = False})
Dim joinFileAndMemoryResources = New JoinBlock(Of FileResource, MemoryResource)(New GroupingDataflowBlockOptions With {.Greedy = False})
' Create two ActionBlock<T> objects.
' The first block acts on a network resource and a memory resource.
' The second block acts on a file resource and a memory resource.
Dim networkMemoryAction = New ActionBlock(Of Tuple(Of NetworkResource, MemoryResource))(Sub(data)
' Perform some action on the resources.
' Print a message.
' Simulate a lengthy operation that uses the resources.
' Print a message.
' Release the resources back to their respective pools.
Console.WriteLine("Network worker: using resources...")
Thread.Sleep(New Random().Next(500, 2000))
Console.WriteLine("Network worker: finished using resources...")
networkResources.Post(data.Item1)
memoryResources.Post(data.Item2)
End Sub)
Dim fileMemoryAction = New ActionBlock(Of Tuple(Of FileResource, MemoryResource))(Sub(data)
' Perform some action on the resources.
' Print a message.
' Simulate a lengthy operation that uses the resources.
' Print a message.
' Release the resources back to their respective pools.
Console.WriteLine("File worker: using resources...")
Thread.Sleep(New Random().Next(500, 2000))
Console.WriteLine("File worker: finished using resources...")
fileResources.Post(data.Item1)
memoryResources.Post(data.Item2)
End Sub)
' Link the resource pools to the JoinBlock<T1, T2> objects.
' Because these join blocks operate in non-greedy mode, they do not
' take the resource from a pool until all resources are available from
' all pools.
networkResources.LinkTo(joinNetworkAndMemoryResources.Target1)
memoryResources.LinkTo(joinNetworkAndMemoryResources.Target2)
fileResources.LinkTo(joinFileAndMemoryResources.Target1)
memoryResources.LinkTo(joinFileAndMemoryResources.Target2)
' Link the JoinBlock<T1, T2> objects to the ActionBlock<T> objects.
joinNetworkAndMemoryResources.LinkTo(networkMemoryAction)
joinFileAndMemoryResources.LinkTo(fileMemoryAction)
' Populate the resource pools. In this example, network and
' file resources are more abundant than memory resources.
networkResources.Post(New NetworkResource())
networkResources.Post(New NetworkResource())
networkResources.Post(New NetworkResource())
memoryResources.Post(New MemoryResource())
fileResources.Post(New FileResource())
fileResources.Post(New FileResource())
fileResources.Post(New FileResource())
' Allow data to flow through the network for several seconds.
Thread.Sleep(10000)
End Sub
End Class
' Sample output:
'File worker: using resources...
'File worker: finished using resources...
'Network worker: using resources...
'Network worker: finished using resources...
'File worker: using resources...
'File worker: finished using resources...
'Network worker: using resources...
'Network worker: finished using resources...
'File worker: using resources...
'File worker: finished using resources...
'File worker: using resources...
'File worker: finished using resources...
'Network worker: using resources...
'Network worker: finished using resources...
'Network worker: using resources...
'Network worker: finished using resources...
'File worker: using resources...
'
Az objektumok megosztott készletének MemoryResource hatékony használatához ez a példa egy GroupingDataflowBlockOptions olyan objektumot határoz meg, amelynek tulajdonsága úgy van Greedy beállítva False , hogy olyan objektumokat hozzon létre JoinBlock<T1,T2> , amelyek nem kapzsi módban működnek. A nem mohó illesztésblokk elhalasztja az összes bejövő üzenetet, amíg az egyes forrásból nem érhető el. Ha az elhalasztott üzeneteket egy másik blokk elfogadta, az illesztésblokk újraindítja a folyamatot. A nem mohó mód lehetővé teszi, hogy az egy vagy több forrásblokkot tartalmazó illesztési blokkok előrehaladjanak, miközben a többi blokk várakozik az adatokra. Ebben a példában, ha egy MemoryResource objektumot adnak hozzá a memoryResources készlethez, az első illesztési blokk, amely a második adatforrást fogadja, előrehaladhat. Ha ez a példa kapzsi módot használna, ami az alapértelmezett, akkor előfordulhat, hogy egy illesztésblokk elérhetővé teszi az MemoryResource objektumot, és megvárja, amíg a második erőforrás elérhetővé válik. Ha azonban a másik illesztési blokk a második adatforrással rendelkezik, nem tud előrehaladni, mert az MemoryResource objektumot a másik illesztési blokk vette át.
Robusztus programozás
A nem mohó illesztések használata segíthet megelőzni a holtpontot az alkalmazásban. Egy szoftveralkalmazásban holtpont akkor fordul elő, ha két vagy több folyamat mindegyike egy erőforrást tárol, és kölcsönösen megvárja, amíg egy másik folyamat más erőforrást bocsát ki. Vegyünk egy alkalmazást, amely két JoinBlock<T1,T2> objektumot határoz meg. Mindkét objektum két megosztott forrásblokkból olvas be adatokat. Mohó módban, ha az egyik illesztésblokk beolvassa az első forrásból, a második pedig a második forrásból olvas be, akkor az alkalmazás holtpontra kerülhet, mert mindkét illesztésblokk kölcsönösen megvárja, amíg a másik felengedi az erőforrást. Nem kapzsi módban az egyes illesztési blokkok csak akkor olvasnak a forrásból, ha minden adat elérhető, ezért a holtpont kockázata megszűnik.